题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1281
思路:把棋盘的行x看成二分图左边的点,列y看成二分图右边的点,那么就把可以放车的位置看成是一条边,而二分图的最大匹配中x互不相同,y互不相同,所以每个匹配都是不同行不同列,所以最大匹配就是最多可以放的车的数量。而要判断有多少个点是必须放的,只要在得出最大匹配后,每次去掉一个匹配,再去运算看得出的结果是否与原来的最大匹配数相同,若相同就不是必须的,若不相同就是必须的。
View Code
1 #include<iostream> 2 const int MAXN=110; 3 using namespace std; 4 int m,n,k; 5 int X[MAXN],Y[MAXN]; 6 int cx[MAXN],cy[MAXN]; 7 int map[MAXN][MAXN]; 8 bool mark[MAXN]; 9 10 int dfs(int u){ 11 //考虑所以yi顶点v 12 for(int v=1;v<=n;v++){ 13 //u与v邻接且没有被访问过 14 if(!mark[v]&&map[u][v]){ 15 mark[v]=1; 16 //如果v没有匹配,或者v已经匹配了,但从cy[v]出发可以找到一条增广路 17 if(cy[v]==-1||dfs(cy[v])){ 18 cy[v]=u;//把u匹配给v 19 cx[u]=v;//把v匹配给u 20 return 1; 21 } 22 } 23 } 24 return 0; 25 } 26 27 //匈牙利算法 28 int MaxMatch(){ 29 int res=0; 30 memset(cx,-1,sizeof(cx));//从1匹配开始增广,将cx,cy各元素初始化为-1. 31 memset(cy,-1,sizeof(cy)); 32 for(int i=1;i<=n;i++){ 33 //从每个未盖点出发寻找增广路 34 if(cx[i]==-1){ 35 memset(mark,false,sizeof(mark)); 36 //每寻找到一条增广路可使匹配数增加1 37 if(dfs(i)){ 38 res++; 39 } 40 } 41 } 42 return res; 43 } 44 45 int main(){ 46 int _case=1; 47 while(~scanf("%d%d%d",&n,&m,&k)){ 48 memset(map,0,sizeof(map)); 49 for(int i=1;i<=k;i++){ 50 scanf("%d%d",&X[i],&Y[i]); 51 map[X[i]][Y[i]]=1; 52 } 53 int ans=MaxMatch();//求二分图最大匹配的匈牙利算法 54 int count=0; 55 for(int i=1;i<=k;i++){ 56 map[X[i]][Y[i]]=0;//试着去掉每一条边 57 int res=MaxMatch(); 58 map[X[i]][Y[i]]=1;//恢复 59 if(res<ans)count++;//如果比先前求出的小,说明是重要点 60 } 61 printf("Board %d have %d important blanks for %d chessmen.\n",_case++,count,ans); 62 } 63 return 0; 64 }