|
83 | 83 | "TravelingSalesman": [Traveling Salesman], |
84 | 84 | "MaximumClique": [Maximum Clique], |
85 | 85 | "MaximumSetPacking": [Maximum Set Packing], |
| 86 | + "MinimumHittingSet": [Minimum Hitting Set], |
86 | 87 | "MinimumSetCovering": [Minimum Set Covering], |
87 | 88 | "ComparativeContainment": [Comparative Containment], |
88 | 89 | "SetBasis": [Set Basis], |
@@ -1823,6 +1824,56 @@ A classical NP-complete problem from Garey and Johnson @garey1979[Ch.~3, p.~76], |
1823 | 1824 | ] |
1824 | 1825 | } |
1825 | 1826 |
|
| 1827 | +#{ |
| 1828 | + let x = load-model-example("MinimumHittingSet") |
| 1829 | + let sets = x.instance.sets |
| 1830 | + let m = sets.len() |
| 1831 | + let U-size = x.instance.universe_size |
| 1832 | + let sol = (config: x.optimal_config, metric: x.optimal_value) |
| 1833 | + let selected = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) |
| 1834 | + let hit-size = sol.metric.Valid |
| 1835 | + let fmt-set(s) = if s.len() == 0 { |
| 1836 | + $emptyset$ |
| 1837 | + } else { |
| 1838 | + "${" + s.map(e => str(e + 1)).join(", ") + "}$" |
| 1839 | + } |
| 1840 | + let elems = ( |
| 1841 | + (-2.0, 0.7), |
| 1842 | + (-0.9, 1.4), |
| 1843 | + (-1.2, -0.4), |
| 1844 | + (0.2, 0.1), |
| 1845 | + (1.2, 1.0), |
| 1846 | + (1.5, -0.9), |
| 1847 | + ) |
| 1848 | + [ |
| 1849 | + #problem-def("MinimumHittingSet")[ |
| 1850 | + Given a finite universe $U$ and a collection $cal(S) = {S_1, dots, S_m}$ of subsets of $U$, find a subset $H subset.eq U$ minimizing $|H|$ such that $H inter S_i != emptyset$ for every $i in {1, dots, m}$. |
| 1851 | + ][ |
| 1852 | + Minimum Hitting Set is one of Karp's 21 NP-complete problems @karp1972. It is the incidence-dual of Set Covering: transposing the set-element incidence matrix swaps the choice of sets with the choice of universe elements. Vertex Cover is the special case in which every set has size $2$, so every edge is "hit" by selecting one of its endpoints. |
| 1853 | + |
| 1854 | + A direct exact algorithm enumerates all $2^n$ subsets $H subset.eq U$ for $n = |U|$ and checks whether each subset intersects every member of $cal(S)$. This yields an $O^*(2^n)$ exact algorithm#footnote[No exact worst-case algorithm improving on brute-force enumeration over the universe elements is recorded in the standard references used for this catalog entry.]. |
| 1855 | + |
| 1856 | + *Example.* Let $U = {1, 2, dots, #U-size}$ and $cal(S) = {#range(m).map(i => $S_#(i + 1)$).join(", ")}$ with #range(m).map(i => $S_#(i + 1) = #fmt-set(sets.at(i))$).join(", "). A minimum hitting set is $H = #fmt-set(selected)$ with $|H| = #hit-size$: every set in $cal(S)$ contains at least one of the selected elements. No $2$-element subset of $U$ hits all #m sets, so the optimum is exactly $#hit-size$. |
| 1857 | + |
| 1858 | + #figure( |
| 1859 | + canvas(length: 1cm, { |
| 1860 | + sregion((elems.at(0), elems.at(1), elems.at(2)), pad: 0.45, label: [$S_1$], ..sregion-dimmed) |
| 1861 | + sregion((elems.at(0), elems.at(3), elems.at(4)), pad: 0.48, label: [$S_2$], ..sregion-dimmed) |
| 1862 | + sregion((elems.at(1), elems.at(3), elems.at(5)), pad: 0.48, label: [$S_3$], ..sregion-dimmed) |
| 1863 | + sregion((elems.at(2), elems.at(4), elems.at(5)), pad: 0.48, label: [$S_4$], ..sregion-dimmed) |
| 1864 | + sregion((elems.at(0), elems.at(1), elems.at(5)), pad: 0.48, label: [$S_5$], ..sregion-dimmed) |
| 1865 | + sregion((elems.at(2), elems.at(3)), pad: 0.34, label: [$S_6$], ..sregion-dimmed) |
| 1866 | + sregion((elems.at(1), elems.at(4)), pad: 0.34, label: [$S_7$], ..sregion-dimmed) |
| 1867 | + for (k, pos) in elems.enumerate() { |
| 1868 | + selem(pos, label: [#(k + 1)], fill: if selected.contains(k) { graph-colors.at(0) } else { black }) |
| 1869 | + } |
| 1870 | + }), |
| 1871 | + caption: [Minimum hitting set: the blue elements $#fmt-set(selected)$ intersect every set region $S_1, dots, S_#m$, so they hit the entire collection $cal(S)$.] |
| 1872 | + ) <fig:min-hitting-set> |
| 1873 | + ] |
| 1874 | + ] |
| 1875 | +} |
| 1876 | + |
1826 | 1877 | #{ |
1827 | 1878 | let x = load-model-example("ConsecutiveSets") |
1828 | 1879 | let m = x.instance.alphabet_size |
|
0 commit comments