hdu Matrix 2119 二分图匹配

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

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




看测试数据:

 
 
3 3 0 0 0 1 0 1 0 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匹配现在这个v
				return 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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值