hdu Matrix 2119 二分图匹配

来源:互联网 发布:glide加载网络图片 编辑:程序博客网 时间:2024/04/19 19:30

题目意思很简单,一个矩阵中用若干个0和1,你一个可以把某一行,或者某一列的1消掉,问你至少要消几次,才能把所有的1全部消除。

二分图匹配的典型例题,不过说话,匈牙利匹配和二分图实在是不好理解,我也看了两三天,才琢磨个差不多。。。希望跟我一样到了大三的朋友们不要放弃ACM,不要堕落下去,多看看,总会看懂的。继续讲题目。把矩阵中每一行看成是二分图左边的一部分,每一列看成是二分图右边的一部分。




看测试数据:

3 3 0 0 01 0 10 1 0
第1行0列,1行2列,2行1列是1,那么变成二分图就是上面那幅图。(画的很挫。。。。)
现在我们的目的是将所有的边消除对不?1行0列是1,我们就要消除1到0这条边,1行2列是1,我们就要消除1到2这条边。但是我们现在一次只能消除一行或者一列,也就是说,我们一次只能消除一个点,比如消除第一行,就是把左边那部分标号为1的点抹掉,只要这个店没了,那么跟她相关的边也没了。现在问题变成了,如何消除最少数量的点,来把所有的边去掉。假设我现在抹掉了左边的点1,毫无疑问,1到0,1到2这两条边都没了。再把左边的点2抹点,2到1这条边也没了,同时,这种方式也是消除最少的点来达到效果的方式。加入你先抹掉右边的点0,那结果就是3了,不满足最小的要求。现在模型转化成了如果用最少的点去覆盖所有的边,这个叫做最小覆盖点。最小覆盖点 = 最大匹配,这是个结论,记得就是啦,要证明的话,网上也有很多。然后现在就来求最大匹配吧。不得不说,匈牙利匹配真让人蛋疼。。。网上大部分的就都只说个大概,一个“显然”,就够让你研究两三天。下面直接贴代码吧。
#include<stdio.h>#include<memory>using namespace std;int n,m,tag[105],pre[105];//邻接表建图。。。。第一次用。。写的不好struct node{int v;node *next;node(int i){v = i;next = 0;}}*map[105]; bool hungary(int k)//匈牙利匹配{node *p = map[k] -> next; //p表示与节点K相连的边while(p)//这。。。就不需要解释了吧。。。链表。。{int v = p -> v;if(!tag[v])  //如果节点v没被接上,{tag[v] = 1;//那就让这个点加入匹配吧。if(pre[v] == -1 || hungary(pre[v]))//如果这个点没有和左边的图中任何一个点相连,那么就让k匹配这个点{              //或者,跟pre【v】,也就是跟v相连的,属于左边那个图的点商量一下,看看左边那个图的点能不能换个点匹配pre[v] = k;//能的话,就让k匹配现在这个vreturn 1;}}p = p -> next;}return 0;}int main(){int a;while(scanf("%d",&n),n){scanf("%d",&m);for(int i = 0;i < n;++i)map[i] = new node(i);memset(pre,-1,sizeof(pre));for(i = 0;i < n;++i)for(int j = 0;j < m;++j){scanf("%d",&a);if(a){node *p = map[i] -> next; //邻接表建图,用链表的头插法。map[i] -> next = new node(j);map[i] -> next -> next = p;}}int ans = 0;for(i = 0;i < n;++i){if(map[i] -> next){memset(tag,0,sizeof(tag));ans += hungary(i);}}printf("%d\n",ans);}return 0;}



原创粉丝点击