分析:该題可以用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 棋盘游戏->二分图最大匹配(匈牙利算法实践)
原文地址:http://blog.csdn.net/a809146548/article/details/45370717