zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    [CSP-S模拟测试]:reverse(模拟)
    BZOJ1559 [JSOI2009]密码 【AC自动机 + 状压dp】
    BZOJ2257 [Jsoi2009]瓶子和燃料 【裴蜀定理】
    BZOJ2729 [HNOI2012]排队 【高精 + 组合数学】
    BZOJ1857 [Scoi2010]传送带 【三分法】
    BZOJ2118 墨墨的等式 【最短路】
    BZOJ5340 [Ctsc2018]假面 【概率dp】
    BZOJ5343 [Ctsc2018]混合果汁 【二分 + 主席树】
    BZOJ4869 [Shoi2017]相逢是问候 【扩展欧拉定理 + 线段树】
    BZOJ2001 [Hnoi2010]City 城市建设 【CDQ分治 + kruskal】
  • 原文地址:https://www.cnblogs.com/LyonLys/p/hdu_1045_Lyon.html
Copyright © 2011-2022 走看看