hdu 2063 过山车 + hdu 2119 Matrix (二分图的最大匹配边和最小覆盖点)

二分图:二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

最大匹配:

给定一个二分图G,M为G边集的一个子集,如果M满足当中的任意两条边都不依附于同一个顶点,则称M是一个匹配。图中包含边数最多的匹配称为图的最大匹配。

最小覆盖点:

无向图中,最少需要多少个点可以覆盖所有的边。一条边被覆盖是指至少有一个和它相邻的点被选中。

特别的,如果该图是二分图,有 最小点覆盖=最大二分匹配。

 

算法:

匈牙利算法. 不断在图中寻找增广路,增广路即路上的边为非匹配边,匹配边,非匹配边,。。。。   然后将匹配边和非匹配边互换可使得匹配边增加, 当找不到增广路时,此时为最大匹配边

http://blog.csdn.net/hackbuteer1/article/details/7398008  这里讲的比较详细

 

例题: hdu 2063 过山车

 

明显裸的二分图最大匹配边

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int map[555][555];//图的表示
int visit[555];//记录改点在这一次寻找增广路中是否已被利用
int match[555];//表示该条匹配边集合N是和集合M的哪个点连接,找到增广路将匹配与非匹边置换时需要
int hash[555];//记录改点是否在图中 
int n,m;

int dfs(int u)
{
	for(int i= 1; i<= m; i++)
		if(map[u][i] && !visit[i])
		{
			visit[i]= 1;
			if(!match[i] || dfs(match[i]))// 找到增广路的条件:!match[i]表示当前只有1条边且为非匹配边,
			{								//dfs(match[i]) 表示找到 非匹配边,匹配边,非匹配边。。此类的情况  
			
				match[i]= u;// 这里相当把匹配边与非匹配边互换 
				return 1;
			}
		}
	return 0;	
}

int main()
{
	int t;
	while(scanf("%d",&t)!=EOF && t)
	{
		memset(map, 0, sizeof(map));
		memset(match, 0, sizeof(match));
		memset(hash, 0, sizeof(hash));
		scanf("%d %d",&n,&m);
		int a,b;
		int sum= 0;
		for(int i= 1; i<= t; i++)
		{
			scanf("%d %d",&a,&b);
			if(!hash[a])
			{
				sum++;
				hash[a]= 1;
			}
			map[a][b]= 1;
		}
		
		int ans= 0;
		for(int i= 1; i<= n; i++)
		{
			memset(visit, 0 ,sizeof(visit));
			if(dfs(i))
				ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
} 
 

 

hdu 2119 Matrix

输入的矩阵可看成一个二分图, map[x][y]= 1表示 集合X中的点1 和集合Y中的点1相连, 最后求最小覆盖点即可

PS:  在二分图中为何最小覆盖点== 最大匹配边  某渣还没搞懂。。。。 

代码:

#include<stdio.h>
#include<string.h>

int map[111][111];
int visit[111];
int match[111];
int m,n;

int dfs(int u)
{
	for(int i= 1; i<= m; i++)
		if(map[u][i] && !visit[i])
		{
			visit[i]= 1;
			if(!match[i] || dfs(match[i]))
			{
				match[i]= u;  //找到增广路,匹配边与非匹配边互换
				return 1; 
			}
		}
	return 0;
}

int main()
{
	while(scanf("%d",&n)!=EOF && n)
	{
		scanf("%d",&m);
		memset(match, 0 ,sizeof(match));
		for(int i= 1; i<= n; i++)
			for(int j= 1; j<= m; j++)
				scanf("%d",&map[i][j]);
		int ans= 0;
		for(int i= 1; i<= n; i++)
		{
			memset(visit, 0, sizeof(visit));
			if(dfs(i))
				ans++; 
		}
		printf("%d\n",ans);
	}
	return 0;
}


 

你可能感兴趣的:(图论)