分析:该題可以用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