棋盘游戏
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 7898 Accepted Submission(s): 4600
Problem Description
小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相攻击,这当然很简单,但是Gardon限制了只有某些格子才可以放,小希还是很轻松的解决了这个问题(见下图)注意不能放车的地方不影响车的互相攻击。
所以现在Gardon想让小希来解决一个更难的问题,在保证尽量多的“车”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量多的“车”被放下。但是某些格子若不放子,就无法保证放尽量多的“车”,这样的格子被称做重要点。Gardon想让小希算出有多少个这样的重要点,你能解决这个问题么?
Input
输入包含多组数据,
第一行有三个数N、M、K(1<N,M<=100 1<K<=N*M),表示了棋盘的高、宽,以及可以放“车”的格子数目。接下来的K行描述了所有格子的信息:每行两个数X和Y,表示了这个格子在棋盘中的位置。
Output
对输入的每组数据,按照如下格式输出:
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.
Author
Gardon
Source
Recommend
lcy
1 /************************************************************************* 2 > File Name: hdu-1281.棋盘游戏.cpp 3 > Author: CruelKing 4 > Mail: [email protected] 5 > Created Time: 2019年08月28日 星期三 09时49分22秒 6 本题思路:本题的重点在于如何求解重要边,最简单的思路就是枚举所有边,如果去掉一条边之后发现最大匹配数目减少了,则说明这条边所对应的点就是关键点。 7 其次还有一种复杂度更低的思路,就是对于每个已经匹配过的边,先删除这条边,我们以所有没有匹配过的顶点为起点再去匹配边,如果发现可以匹配到那么就说明还可以找到其他增广路,意思就是可以有别的匹配边代替这条匹配边,那么这个点就不是关键点,否则这个点就是关键点。 8 ************************************************************************/ 9 /* 10 #include <cstdio> 11 #include <cstring> 12 using namespace std; 13 14 const int maxn = 100 + 5, maxm = 100 * 100 + 5; 15 int linker[maxn], ui[maxn], vi[maxn]; 16 bool used[maxn], g[maxn][maxn]; 17 int n, m; 18 19 bool dfs(int u) { 20 for(int v = 1; v <= m; v ++) { 21 if(g[u][v] && !used[v]) { 22 used[v] = true; 23 if(linker[v] == -1 || dfs(linker[v])) { 24 linker[v] = u; 25 return true; 26 } 27 } 28 } 29 return false; 30 } 31 32 int hungary() { 33 int res = 0; 34 memset(linker, -1, sizeof linker); 35 for(int i = 1; i <= n; i ++) { 36 memset(used, false, sizeof used); 37 if(dfs(i)) res ++; 38 } 39 return res; 40 } 41 42 int main() { 43 int k, u, v, Case = 0; 44 while(~scanf("%d %d %d", &n, &m, &k)) { 45 memset(g, false, sizeof g); 46 for(int i = 0; i < k; i ++) { 47 scanf("%d %d", &ui[i], &vi[i]); 48 g[ui[i]][vi[i]] = true; 49 } 50 int res1 = hungary(), cnt = 0; 51 for(int i = 0; i < k; i ++) { 52 g[ui[i]][vi[i]] = false; 53 int res2 = hungary(); 54 if(res2 < res1) cnt ++; 55 g[ui[i]][vi[i]] = true; 56 } 57 printf("Board %d have %d important blanks for %d chessmen.\n", ++ Case, cnt, res1); 58 } 59 return 0; 60 } 61 */ 62 63 #include <cstdio> 64 #include <cstring> 65 using namespace std; 66 67 const int maxn = 100 + 5; 68 int n, m, k; 69 int linkery[maxn], linkerx[maxn]; 70 bool used[maxn], g[maxn][maxn]; 71 bool flag; 72 73 bool dfs(int u) { 74 for(int v = 1; v <= m; v ++) { 75 if(g[u][v] && !used[v]) { 76 used[v] = true; 77 if(linkery[v] == -1 || dfs(linkery[v])) { 78 if(flag) { 79 linkery[v] = u; 80 linkerx[u] = v; 81 } 82 return true; 83 } 84 } 85 } 86 return false; 87 } 88 89 int hungary() { 90 flag = true; 91 memset(linkery, -1, sizeof linkery); 92 memset(linkerx, -1, sizeof linkerx); 93 int res = 0; 94 for(int i = 1; i <= n; i ++) { 95 memset(used, false, sizeof used); 96 if(dfs(i)) res ++; 97 } 98 return res; 99 } 100 101 bool can() { 102 flag = false; 103 for(int u = 1; u <= n; u ++) { 104 if(linkerx[u] == -1) { 105 memset(used, false, sizeof used); 106 if(dfs(u)) return true; 107 } 108 } 109 return false; 110 } 111 112 int main() { 113 int u, v, Case = 0; 114 while(~scanf("%d %d %d", &n, &m, &k)) { 115 memset(g, false, sizeof g); 116 for(int i = 0; i < k; i ++) { 117 scanf("%d %d", &u, &v); 118 g[u][v] = true; 119 } 120 int ans = hungary(); 121 int res = 0, temp; 122 for(int i = 1; i <= n; i ++) { 123 if(~linkerx[i]) { 124 temp = linkerx[i]; 125 linkerx[i] = linkery[temp] = -1; 126 g[i][temp] = false; 127 if(!can()) res ++; 128 linkerx[i] = temp; 129 linkery[temp] = i; 130 g[i][temp] = true; 131 } 132 } 133 printf("Board %d have %d important blanks for %d chessmen.\n", ++ Case, res, ans); 134 } 135 return 0; 136 }
原文地址:https://www.cnblogs.com/bianjunting/p/11423276.html