码迷,mamicode.com
首页 > 编程语言 > 详细

HDU ACM 1281 棋盘游戏->二分图最大匹配(匈牙利算法实践)

时间:2015-04-29 21:49:17      阅读:464      评论:0      收藏:0      [点我收藏+]

标签:c   c++   acm   算法   图论   

分析:该題可以用x坐标去匹配y坐标,匹配成功一次就是一个可放棋子的点,最后求得的的二分图最大匹配就是可以放的最大棋子数。求二分图的最大匹配使用匈牙利算法。之后通过删除一条边来判断一个点是否为关键点,若删边后,最大匹配数不变则不是,否则是,通过分别删除每个点进行测试,最终即可算出关键点的个数。

#include<iostream>
using namespace std;

#define N 102
int map[N][N];    //记录连接x和y的边
bool vis[N];      //记录y中节点是否使用过
int link[N];      //记录当前与y节点相连的x的节点

int FindMatch(int u,int m)  //发现匹配
{
	int i;

	for(i=1;i<=m;i++)
		if(map[u][i]==1 && !vis[i])
		{
			vis[i]=true;
			if(link[i]==-1 || FindMatch(link[i],m)) //FindMatch(link[i],m)为重新匹配之前匹配过的
			{
				link[i]=u;
				return 1;
			}
		}
	return 0;
}

void KeyPointAndMatchCount(int& keypoint,int &match,int n,int m)
{
	int i,j,ans,k;

	match=0;
	memset(link,-1,sizeof(link));       //求出二分图的最大匹配
	for(i=1;i<=n;i++)    //用x去匹配y
	{
		memset(vis,false,sizeof(vis));
		match+=FindMatch(i,m);
	}

	keypoint=0;
	for(i=1;i<=n;i++)              //通过删除关键边
		for(j=1;j<=m;j++)
		{
			ans=0;
			if(map[i][j]==1)
			{
				memset(link,-1,sizeof(link));
				map[i][j]=0;
				for(k=1;k<=n;k++)
				{
					memset(vis,false,sizeof(vis));
	            	ans+=FindMatch(k,m);
				}
				map[i][j]=1;
				if(ans!=match)       //匹配不等则为一关键点
					keypoint++;
			}
		}
}

int main()
{
	int n,M,K,X,Y;
	int T,keypoint,match,i;

	T=0;
	while(scanf("%d %d %d",&n,&M,&K)==3)
	{
		memset(map,0,sizeof(map));
		for(i=0;i<K;i++)
		{
			scanf("%d %d",&X,&Y);
			map[X][Y]=1;
		}
		KeyPointAndMatchCount(keypoint,match,n,M);
		printf("Board %d have %d important blanks for %d chessmen.\n",++T,keypoint,match);
	}
    return 0;
}


HDU ACM 1281 棋盘游戏->二分图最大匹配(匈牙利算法实践)

标签:c   c++   acm   算法   图论   

原文地址:http://blog.csdn.net/a809146548/article/details/45370717

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!