POJ 1274 The Perfect Stall(最大二分匹配)

关于二分匹配算法的介绍,推荐这个博客网址,写得非常漂亮

http://chhaj5236.blog.163.com/blog/static/1128810812009910102617216/

感谢这位博主给我很大的启示,以及JSH同学的大力详细讲解。

//最大二分匹配——匈牙利算法 复杂度O(VE) //对匈牙利算法的直观理解: //二分图两部分,左边和右边,要找最大匹配数,左边为u,右边为v //从u1出发,找到一个点相连我就连上去,假设是v1 //接着u2出发,发现我和v1也可以相连啊,u2不能这样就放弃v1,所以u2告诉u1,你去找别人连,找得到v1给我,这样大家双赢,匹配数+1 //u1去找的时候呢,记住把v1设为待定状态,也就是有人先定了……防止后面抢对象的混乱局面。也就是我程序里面的check数组 //u1如果找不到,那么我u2放弃,找v2看行不行 //可以通过反证法证明这样的找对象方法最后的出来的匹配数是最大的 #include<iostream> #include<cstring> using namespace std; const int MAXN = 205; bool g[MAXN][MAXN];//连通矩阵 int uMatch[MAXN],vMatch[MAXN];//与u匹配的点编号,与v匹配的点编号 int U,V;//二分图左边结点数和右边结点数 int max_match;//最大二分匹配数 bool check[MAXN];//检查状态的数组 bool findPath(int u) //找增广路函数,他的返回值是是否找到增广路 { for(int v = 0;v < V;++v) { if(g[u][v] && !check[v])//如果连通,并且未处于被检查状态。检查状态意味着之前有人想连这个结点v,但是在等findPath函数告诉我和v相连的这家伙是否找到其他的路,如果找到我就和v连上去,此时匹配数必定多1 { check[v] = true;//这时候v处于被检查状态 if(vMatch[v] == -1 || findPath(vMatch[v]))//如果v没人和他连,那我直接连上去。有人和他连,那我就叫和他连的家伙去找其他人连,找得到,我就连v,找不到,那我放弃v,连v+1看行不行 { vMatch[v] = u;//记录u和v相连 uMatch[u] = v;//记录v和u相连 return true; } } } return false;//如果我扫描了v发现找不到增广路,就返回找不到咯 } int main() { //freopen("in.txt","r",stdin); while(scanf("%d%d",&U,&V) != EOF) { max_match = 0; memset(g,0,sizeof(g)); memset(uMatch,-1,sizeof(uMatch)); memset(vMatch,-1,sizeof(vMatch));//初始化 for(int i = 0;i < U;++i) { int match_num; scanf("%d",&match_num); for(int j = 0;j < match_num;++j) { int k; scanf("%d",&k); g[i][k-1] = 1;//注意是k-1,编号是从0开始的 }//读入连通状态 } for(int u = 0;u < U;++u)//从u这边开始 { if(uMatch[u] == -1) { memset(check,0,sizeof(check));//记住检查状态是在找增广路的过程中有效的,不是永久有效,所以必须每次从u出发找增广路时就初始化一次 if(findPath(u)) max_match++; } } printf("%d/n",max_match); } return 0; } 

你可能感兴趣的:(算法)