题目:POJ 3041 Asteroids http://poj.org/problem?id=3041
分析:
把位置下标看出一条边,这显然是一个二分图最小顶点覆盖的问题,Hungary就好。
挑战:
输出一组可行解。构造,已知二分图的两个点集U和V,s-U-V-t,在最大匹配的残留网络里,选从s出发能到达的V中的点
沿途可以到达的U集中的点的路径就都被覆盖了,然后在选择U集合中无法到达的点。对于二分图中任意一条边,其中必有一点属于U集合,
所以前面选出的点集S是一个覆盖。并且S中V和U对应的匹配边是相斥的,总数确实等于总匹配边数。(更具体的,可以想想U是怎么划分的。)
如果最大匹配数记为M,最小点覆盖记为C。那么的构造还可以说明M≥C。又因为匹配边是平行的,所以至少要M个点才能覆盖,C≥M。这样
就得出了M = C的结论。
Code
/********************************************************* * ------------------ * * author AbyssalFish * **********************************************************/ #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<queue> #include<vector> #include<stack> #include<vector> #include<map> #include<set> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const int maxn = 501, maxm = 1e4+1; int hd[maxn],to[maxm],nx[maxm],ec; #define eachEage int i = hd[u]; i; i = nx[i] void add(int u,int v) { nx[++ec] = hd[u]; to[ec] = v; hd[u] = ec; } int link[maxn]; int vis[maxn], clk; bool dfs(int u) { vis[u] = clk; for(eachEage){ int v = to[i], w = link[v]; if(!w || (vis[w]!=clk && dfs(w))){ link[v] = u; return true; } } return false; } //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif int n,k; scanf("%d%d",&n,&k); for(int i = 0; i < k; i++){ int r, c; scanf("%d%d",&r,&c); add(r,c); } int ans = 0; for(int i = 1; i <= n; i++){ clk++; if(dfs(i)) ans++; } printf("%d ", ans); return 0; }