题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1281
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Problem Description
小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相攻击,这当然很简单,但是Gardon限制了只有某些格子才可以放,小希还是很轻松的解决了这个问题(见下图)注意不能放车的地方不影响车的互相攻击。
所以现在Gardon想让小希来解决一个更难的问题,在保证尽量多的“车”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量多的“车”被放下。但是某些格子若不放子,就无法保证放尽量多的“车”,这样的格子被称做重要点。Gardon想让小希算出有多少个这样的重要点,你能解决这个问题么?
所以现在Gardon想让小希来解决一个更难的问题,在保证尽量多的“车”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量多的“车”被放下。但是某些格子若不放子,就无法保证放尽量多的“车”,这样的格子被称做重要点。Gardon想让小希算出有多少个这样的重要点,你能解决这个问题么?
Input
输入包含多组数据,
第一行有三个数N、M、K(1<N,M<=100 1<K<=N*M),表示了棋盘的高、宽,以及可以放“车”的格子数目。接下来的K行描述了所有格子的信息:每行两个数X和Y,表示了这个格子在棋盘中的位置。
第一行有三个数N、M、K(1<N,M<=100 1<K<=N*M),表示了棋盘的高、宽,以及可以放“车”的格子数目。接下来的K行描述了所有格子的信息:每行两个数X和Y,表示了这个格子在棋盘中的位置。
Output
对输入的每组数据,按照如下格式输出:
Board T have C important blanks for L chessmen.
Board T have C important blanks for L chessmen.
Sample Input
3 3 4
1 2
1 3
2 1
2 2
3 3 4
1 2
1 3
2 1
3 2
Sample Output
Board 1 have 0 important blanks for 2 chessmen.
Board 2 have 3 important blanks for 3 chessmen.
题解:
因为这次没有墙能隔开车与车之间的攻击,故直接将整行整列缩成点,然后求出max match;
但是如何寻找其中的“必须边”呢?
比较好想的方法就是直接暴力枚举最大匹配中的匹配边,如果把它去掉还能不能得到一样的最大匹配数:
如果不能,就是必须边,cnt+=1;
AC代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #define MAX 203 5 using namespace std; 6 int n,m,k; 7 int edge[MAX][MAX]; 8 int matching[MAX]; 9 int vis[MAX]; 10 void init(){memset(edge,0,sizeof(edge));} 11 void add_edge(int u,int v){edge[u][v]=edge[v][u]=1;} 12 bool dfs(int u) 13 { 14 for(int v=1;v<=n+m;v++) 15 { 16 if(!edge[u][v]) continue; 17 if (!vis[v]) 18 { 19 vis[v]=1; 20 if(!matching[v] || dfs(matching[v])) 21 { 22 matching[v]=u; 23 matching[u]=v; 24 return true; 25 } 26 } 27 } 28 return false; 29 } 30 int hungarian() 31 { 32 int ret=0; 33 memset(matching,0,sizeof(matching)); 34 for(int i=1;i<=n;i++) 35 { 36 if(!matching[i]) 37 { 38 memset(vis,0,sizeof(vis)); 39 if(dfs(i)) ret++; 40 } 41 } 42 return ret; 43 } 44 int mp[103][103],match[MAX][MAX]; 45 int main() 46 { 47 int kase=0; 48 while(scanf("%d%d%d",&n,&m,&k)!=EOF) 49 { 50 memset(mp,0,sizeof(mp)); 51 for(int i=1,r,c;i<=k;i++) 52 { 53 scanf("%d%d",&r,&c); 54 mp[r][c]=1; 55 } 56 57 init(); 58 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(mp[i][j]) add_edge(i,j+n); 59 int max_match=hungarian(); 60 61 int cnt=0; 62 memset(match,0,sizeof(match)); 63 for(int i=1;i<=n+m;i++) for(int j=n+1;j<=n+m;j++) if(matching[i]==j && matching[j]==i) match[i][j]=1; 64 for(int i=1;i<=n+m;i++) 65 { 66 for(int j=n+1;j<=n+m;j++) 67 { 68 if(match[i][j]) 69 { 70 edge[i][j]=0; 71 if(hungarian()<max_match) cnt++; 72 edge[i][j]=1; 73 } 74 } 75 } 76 77 printf("Board %d have %d important blanks for %d chessmen. ",++kase,cnt,max_match); 78 } 79 }