http://acm.hdu.edu.cn/showproblem.php?pid=1045
这题题意是找到尽可能多的点,使它们相互之间都不在同一条无阻隔的水平或竖直线上。
如果将可操作点作为集合,那么这题就是一道最大独立集的问题,所以可以直接套最大匹配的算法。当然,这题根据也可以将图取反,然后求最大团。
列举一些性质:
最大独立集 + 最小覆盖集 = V
最大团 = 补图的最大独立集
最小覆盖集 = 最大匹配
下面的是用最大匹配hk算法来做的:
View Code
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cmath> 5 6 using namespace std; 7 8 bool mp[4][4], rel[8][8], vis[8]; 9 int r[4][4], c[4][4]; 10 int dx[8], dy[8], mx[8], my[8]; 11 int q[20], ff, bb; 12 13 bool bfs(int n, int m){ 14 bool ret = false; 15 16 for (int i = 0; i < m; i++) dy[i] = 0; 17 ff = bb = 0; 18 for (int i = 0; i < n; i++){ 19 dx[i] = 0; 20 if (mx[i] == -1) q[bb++] = i, vis[i] = true; 21 else vis[i] = false; 22 } 23 24 while (ff != bb){ 25 int cur = q[ff++]; 26 27 vis[cur] = false; 28 for (int i = 0; i < m; i++){ 29 if (rel[cur][i] && !dy[i]){ 30 dy[i] = dx[cur] + 1; 31 if (my[i] == -1){ 32 ret = true; 33 } 34 else{ 35 dx[my[i]] = dy[i] + 1; 36 if (!vis[my[i]]){ 37 vis[my[i]] = true; 38 q[bb++] = my[i]; 39 } 40 } 41 } 42 } 43 } 44 45 return ret; 46 } 47 48 bool dfs(int cur, int m){ 49 for (int i = 0; i < m; i++){ 50 if (rel[cur][i] && dy[i] == dx[cur] + 1){ 51 dy[i] = 0; 52 if (my[i] == -1 || dfs(my[i], m)){ 53 mx[cur] = i; 54 my[i] = cur; 55 56 return true; 57 } 58 } 59 } 60 61 return false; 62 } 63 64 int hk(int n, int m){ 65 int cnt = 0; 66 67 for (int i = 0; i < n; i++) mx[i] = -1; 68 for (int i = 0; i < m; i++) my[i] = -1; 69 while (bfs(n, m)){ 70 for (int i = 0; i < n; i++){ 71 if (mx[i] == -1 && dfs(i, m)) cnt++; 72 } 73 } 74 #ifndef ONLINE_JUDGE 75 for (int i = 0; i < n; i++){ 76 printf("x %d y %d\n", mx[i], my[i]); 77 } 78 #endif 79 80 return cnt; 81 } 82 83 84 void con(int n, int &a, int &b){ 85 int cnt; 86 87 cnt = 0; 88 for (int i = 0; i < n; i++){ 89 for (int j = 0; j < n; j++){ 90 if (!mp[i][j]){ 91 if (!j){ 92 r[i][j] = ++cnt; 93 } 94 else{ 95 r[i][j] = abs(r[i][j - 1]); 96 } 97 } 98 else{ 99 if (!j || !mp[i][j - 1]){ 100 r[i][j] = -(++cnt); 101 } 102 else{ 103 r[i][j] = r[i][j - 1]; 104 } 105 } 106 } 107 } 108 a = cnt; 109 110 cnt = 0; 111 for (int i = 0; i < n; i++){ 112 for (int j = 0; j < n; j++){ 113 if (!mp[j][i]){ 114 if (!j){ 115 c[j][i] = ++cnt; 116 } 117 else{ 118 c[j][i] = abs(c[j - 1][i]); 119 } 120 } 121 else{ 122 if (!j || !mp[j - 1][i]){ 123 c[j][i] = -(++cnt); 124 } 125 else{ 126 c[j][i] = c[j - 1][i]; 127 } 128 } 129 } 130 } 131 b = cnt; 132 133 #ifndef ONLINE_JUDGE 134 for (int i = 0; i < n; i++){ 135 for (int j = 0; j < n; j++){ 136 printf("%d:%d ", r[i][j], c[i][j]); 137 } 138 puts(""); 139 } 140 #endif 141 for (int i = 0; i < a; i++){ 142 for (int j = 0; j < b; j++){ 143 rel[i][j] = false; 144 } 145 } 146 for (int i = 0; i < n; i++){ 147 for (int j = 0; j < n; j++){ 148 if (r[i][j] <= 0) continue; 149 rel[r[i][j] - 1][c[i][j] - 1] = true; 150 } 151 } 152 #ifndef ONLINE_JUDGE 153 for (int i = 0; i < a; i++){ 154 for (int j = 0; j < b; j++){ 155 printf("%d", rel[i][j]); 156 } 157 puts(""); 158 } 159 #endif 160 161 } 162 163 bool deal(){ 164 int n, a, b; 165 char ch; 166 167 scanf("%d", &n); 168 ch = getchar(); 169 if (!n) return false; 170 for (int i = 0; i < n; i++){ 171 while (ch != '.' && ch != 'X')ch = getchar(); 172 for (int j = 0; j < n; j++){ 173 mp[i][j] = (ch == 'X'); 174 ch = getchar(); 175 } 176 } 177 con(n, a, b); 178 #ifndef ONLINE_JUDGE 179 printf("a %d b %d\n", a, b); 180 #endif 181 printf("%d\n", hk(a, b)); 182 183 return true; 184 } 185 186 int main(){ 187 #ifndef ONLINE_JUDGE 188 freopen("in", "r", stdin); 189 #endif 190 while (deal()); 191 192 return 0; 193 }
用这个算法当然是大材小用,不过我是当作再次练习hk算法来打的。代码途中又是意外打错了一个字,所以debug了很久才改过来。相信练习多几次应该就可以很快debug出问题,甚至是避免这样的错误了。这个代码比较恶心,处理比较多,相信如果用最大团应该会简洁点吧!
最大团算法:
View Code
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 5 const int maxn = 20; 6 bool maz[maxn][maxn]; 7 int dp[maxn], best; 8 int mp[4][4]; 9 10 bool dfs(int n, int *u, int deep){ 11 int i, j, vn, v[maxn]; 12 if (n){ 13 if (deep + dp[u[0]] <= best) return false; 14 for (i = 0; i < n + deep - best && i < n; i++){ 15 for (vn = 0, j = i + 1; j < n; j++){ 16 if (maz[u[i]][u[j]]) v[vn++] = u[j]; 17 } 18 if (dfs(vn, v, deep + 1)) return true; 19 } 20 } 21 else if (deep > best){ 22 best = deep; 23 return true; 24 } 25 26 return false; 27 } 28 29 int maxclique(int n){ 30 int i, j, vn, v[maxn]; 31 32 best = 0; 33 dp[n - 1] = 0; 34 for (i = n - 1; i >= 0; i--){ 35 for (vn = 0, j = i + 1; j < n; j++){ 36 if (maz[i][j]) v[vn++] = j; 37 } 38 dfs(vn, v, 1); 39 dp[i] = best; 40 } 41 42 return best; 43 } 44 45 bool judge(int x, int y, int i, int j){ 46 int t; 47 48 if (x == i){ 49 if (y > j){ 50 y ^= j; 51 j ^= y; 52 y ^= j; 53 } 54 for (t = y + 1; t < j; t++){ 55 if (!mp[i][t]) return false; 56 } 57 } 58 if (y == j){ 59 if (x > i){ 60 x ^= i; 61 i ^= x; 62 x ^= i; 63 } 64 for (t = x + 1; t < i; t++){ 65 if (!mp[t][j]) return false; 66 } 67 } 68 if (x != i && y != j) return false; 69 70 return true; 71 } 72 73 int con(int n){ 74 int cnt = 0; 75 76 for (int i = 0; i < n; i++){ 77 for (int j = 0; j < n; j++){ 78 if (mp[i][j]) mp[i][j] = ++cnt; 79 #ifndef ONLINE_JUDGE 80 printf("%d ", mp[i][j]); 81 #endif 82 } 83 #ifndef ONLINE_JUDGE 84 puts(""); 85 #endif 86 } 87 for (int i = 0; i < n; i++){ 88 for (int j = 0; j < n; j++){ 89 if (mp[i][j]){ 90 for (int p = 0; p < n; p++){ 91 for (int q = 0; q < n; q++){ 92 if (mp[i][j] == mp[p][q] || !mp[p][q]) continue; 93 if (judge(i, j, p, q)) continue; 94 maz[mp[i][j] - 1][mp[p][q] - 1] = true; 95 #ifndef ONLINE_JUDGE 96 printf("%d %d\n", mp[i][j] - 1, mp[p][q] - 1); 97 #endif 98 } 99 } 100 } 101 } 102 } 103 104 return cnt; 105 } 106 107 bool deal(){ 108 int n; 109 char ch; 110 111 scanf("%d", &n); 112 ch = getchar(); 113 if (!n) return false; 114 for (int i = 0; i < n; i++){ 115 while (ch != '.' && ch != 'X')ch = getchar(); 116 for (int j = 0; j < n; j++){ 117 mp[i][j] = (ch != 'X' ? 1 : 0); 118 ch = getchar(); 119 } 120 } 121 memset(maz, false, sizeof(maz)); 122 n = con(n); 123 printf("%d\n", maxclique(n)); 124 125 return true; 126 } 127 128 129 int main(){ 130 #ifndef ONLINE_JUDGE 131 freopen("in", "r", stdin); 132 #endif 133 while (deal()); 134 135 return 0; 136 }
在这题不能看出两种方法的差别,不过可以看到用最大团算法写可以明显减少代码量。不过还是写的有些恶心.....- -
——written by Lyon