hdu 1045 Fire Net

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

原文地址:https://www.cnblogs.com/LyonLys/p/hdu_1045_Lyon.html