结论:
建图一般都是分为两部分建立二分图,混杂着不分部分会出现各种错误.
①最小点覆盖数 = 最大匹配数
②二分图中最大独立集+最小顶点覆盖(最大匹配)=顶点数
③最小边覆盖 = 最大独立集 = n - 最大匹配数
证明:设最大匹配数为m,总顶点数为n。为了使边数最少,又因为一条边最多能干掉两个点,所以尽量用边干掉两个点。也就是取有匹配的那些边,当然这些边是越多越好,那就是最大匹配了,所以先用最大匹配数目的边干掉大多数点。剩下的解决没有被匹配的点,就只能一条边干掉一个点了,设这些数目为a,显然,2m+a=n,而最小边覆盖=m+a,所以最小边覆盖=(2m+a)-m=n-m。
④最小路径覆盖,不要求给的图是二分图,而是要求是PXP的有向图无环图,然后根据原图构造二分图,构造方法是将点一分为二,如,i分为i1和i2然后如果i和j有边,那么就在i1和j2之间连一条边。由此构成二分图,其实就是把本来的n个点分为n个男孩和点n个女孩.
然后最小路径覆盖是n-m,n为原图的点的个数,m为新造二分图的最大匹配。
⑤无向图G(V,E)边覆盖的求解步骤:
1.将无向图拆点,即若在无向图中存在节点i,则将节点i拆为i1,i2分别位于二分图的X部和Y部.若存在边ij,则连接二分图的i1j2,i2j1。
2.原无向图中的节点数为|V|所以在构造的二分图有2*|V|个节点。在二分图中存在公式:
2*|V| = 2*二分图的最大匹配数 + 二分图中未匹配的点。其中二分图的最大匹配数+二分图中未匹配的点即覆盖了二分图中所有的点,相对于原无向图,相当于覆盖了每个点两次,即原边覆盖的最小值转化为二分图的最大匹配数+二分图中未匹配的点的最小值。又有公式2*|V| = 2*二分图的最大匹配数 + 二分图中未匹配的点,可得:
二分图的最大匹配数+二分图中未匹配的点 = 2*|V| - 二分图的最大匹配数,又此结果为覆盖了原图所有顶点两次,所以结果应该除以2.
所以无向图的最小边覆盖 = |V| - 二分图的最大匹配数/2.
匈牙利算法讲解:点击打开链接
板子:
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 1000000007
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const double esp = 1e-7;
const int ff = 0x3f3f3f3f;
map<int,int>::iterator it;
int n,m,k;
int mp[520][520];
int vis[520];
int g[520];
int find(int x)
{
for(int i = 1;i<= n;i++)
{
if(mp[x][i]&&!vis[i])
{
vis[i] = 1;
if(!g[i]||find(g[i]))
{
g[i] = x;
return 1;
}
}
}
return 0;
}
void init()
{
mem(mp,0);
mem(g,0);
}
int main()
{
int t;
cin>>t;
while(t--)
{
init();
scanf("%d %d",&m,&n);
for(int i = 1;i<= m;i++)
{
int a,b;
scanf("%d %d",&a,&b);
mp[a][b] = 1;
}
int ans = 0;
for(int i = 1;i<= m;i++)
{
mem(vis,0);
if(find(i))
ans++;
}
cout<<ans<<endl;
}
return 0;
}