貌似是我想少了,二分图不止只有最大匹配,先写一些结论吧,等着总结一下。
参考: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;
}