题目: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 LOCALfreopen("in.txt","r",stdin); #endifint 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\n", ans);return 0; }