【bzoj1143】 CTSC2008祭祀river 二分图匹配

貌似是我想少了,二分图不止只有最大匹配,先写一些结论吧,等着总结一下。

参考:http://endlesscount.blog.163.com/blog/static/821197872012622103810976/

二分图最小点覆盖(每条边至少一个顶点在集合里)=最大匹配

二分图最小边覆盖(每个点至少连一条边)=二分图点数-最大匹配

证明:考虑最大匹配后,每个未匹配的点连出一条边,即为最小边覆盖=二分图点数-2*最大匹配+最大匹配=二分图点数-最大匹配。

二分图最大独立集(点两两无边)=二分图点数-最小点覆盖

有向无环图最小不相交路径覆盖

  把原图中的每个点V拆成Vx和Vy,如果有一条有向边A->B,那么就加边Ax-By。这样就得到了一个二分图,最小路径覆盖=原图的节点数-新图最大匹配。
        简单证明:一开始每个点都独立的为一条路径,总共有n条不相交路径。我们每次在二分图里加一条边就相当于把两条路径合成了一条路径,因为路径之间不能有公共点,所以加的边之间也不能有公共点,这就是匹配的定义。所以有:最小路径覆盖=原图的节点数-新图最大匹配。
有向无环图最小可相交路径覆盖
先floyd求出连通性后,最小不相交路径覆盖。

这道题是裸的二分图最大独立集,对于原图的点x、y,如果联通,则从ax向by连一条边,最后要求选中的点之间没有连边即求最大独立集。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 110

using namespace std;

int a[maxn][maxn],lk[maxn],f[maxn][maxn];
bool vis[maxn];
int n,m;

bool find(int x)
{
	for (int i=1;i<=n;i++)
	  if (a[x][i] && !vis[i])
	  {
	  	vis[i]=1;
	  	if (!lk[i] || find(lk[i]))
	  	{
	  		lk[i]=x;
	  		return 1;
	  	}
	  }
	return 0;
}

int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		f[x][y]=1;
	}
	for (int k=1;k<=n;k++)
	  for (int i=1;i<=n;i++)
	    for (int j=1;j<=n;j++)
	      f[i][j]|=f[i][k]&&f[k][j];
	for (int i=1;i<=n;i++)
	  for (int j=1;j<=n;j++)
	    if (f[i][j] && i!=j) a[i][j]=1;
	int ans=n;
	for (int i=1;i<=n;i++)
	{
		memset(vis,0,sizeof(vis));
		if (find(i)) ans--;
	}
	printf("%d\n",ans);
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值