二分图结论+板子

结论:

建图一般都是分为两部分建立二分图,混杂着不分部分会出现各种错误.

①最小点覆盖数 = 最大匹配数

②二分图中最大独立集+最小顶点覆盖(最大匹配)=顶点数

③最小边覆盖 = 最大独立集 = 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;
}

猜你喜欢

转载自blog.csdn.net/nka_kun/article/details/79904697