hdu 1151 最小覆盖路径算法证明

又是二分图。若还不知道匈牙利算法,看我前面的文章

先把每个点拆成两个,一个表示出,一个表示入,根据数据输入,对应的出点和对应入点之间构造了一条边。这样就有了一个二分图。

有向图的最小路径覆盖 = 总的点数(为拆分前的) - 最大匹配数。

证明如下:

先假设所有点我们都派出一个伞兵。然后每增加一条匹配,就代表我们从一个点出走向一个点。并且根据最大匹配的定义,我们可以直接看作是将这两个点合并到一个路径集合中,这个时候我们就可以减少一个伞兵。 所以 路径覆盖 = 总的点数 - 最大匹配数 。

然而这样我们并没有证明 是 “最小”覆盖。 接下来证明最小。 假设 不是最小,那么也就意味着还可以减少伞兵,而减少伞兵就必须合并某两个点(即匹配),而匹配已经最大,所以矛盾。

即 需要派遣的伞兵数 = 总点数 - 匹配数。    最少伞兵派遣 = 总点数 - 最大匹配数。

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string.h>
#define base 10
using namespace std;
bool vis[130],map[130][130];
int match[130],n,m;
bool find(int p)
{
	int i,j;
	for(i = 1; i <= m; i++)
	{
		if(!vis[i] && map[p][i])
		{
			vis[i] = 1;
			if( !match[i] || find(match[i])) 
			{
				match[i] = p;
				return 1;
			}
		}
	}
	return 0;
}
int main()
{
//	freopen("t.txt","r",stdin);
	int k,i,j,count,t,a,b;	
	scanf("%d",&t);
	while(t--)
	{
		memset(map,0,sizeof(map));
		memset(match,0,sizeof(match));
		count = 0;
		scanf("%d%d",&m,&n);//m 点, n 边 
		for(i = 0; i < n; i++)
		{
			scanf("%d%d",&a,&b);
			map[a][b] = 1;
		}
		for(i = 1; i <= m; i++)
		{
			memset(vis,0,sizeof(vis));
			if(find(i)) count++;
		}
		printf("%d\n",m-count);
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值