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

来源:互联网 发布:java 哪里用到反射 编辑:程序博客网 时间:2024/05/01 01:20

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

#include<iostream>using namespace std;#define N 102int 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;}


0 0