插头DP

一般是求网格图路径个数/最值的。

维护轮廓线连通性。按照格子转移。

参考资料题单

注意跨行时的转移。

例题:bzoj1814  注意!结尾不一定是(n, m),此时要保证没有插头才能加入答案。

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <cmath>
  5 
  6 typedef long long LL;
  7 const int N = 14, M = 1600000;
  8 
  9 LL f[2][M];
 10 int n, m, G[N][N], now[N], state[M], id[M], top;
 11 char str[N];
 12 
 13 inline int zip(int *a) {
 14     int ans = 0;
 15     for(int i = m; i >= 0; i--) {
 16         ans = ans * 3 + a[i];
 17     }
 18     return id[ans];
 19 }
 20 
 21 inline void DFS(int k, int cnt, int sta) {
 22     if(k > m) {
 23         if(cnt == 0) {
 24             state[++top] = sta;
 25             id[sta] = top;
 26             //printf("state ++top = %d \n", state[top]);
 27         }
 28         return;
 29     }
 30     DFS(k + 1, cnt, sta * 3);
 31     if(cnt) {
 32         DFS(k + 1, cnt - 1, sta * 3 + 1);
 33     }
 34     DFS(k + 1, cnt + 1, sta * 3 + 2);
 35     return;
 36 }
 37 
 38 inline void prework() {
 39     DFS(0, 0, 0);
 40     return;
 41 }
 42 
 43 inline void unzip(int x, int *a) { // m + 1
 44     x = state[x];
 45     for(int i = 0; i <= m; i++) {
 46         a[i] = x % 3;
 47         x /= 3;
 48     }
 49     return;
 50 }
 51 
 52 inline void add(LL &a, LL b) {
 53     a += b;
 54     return;
 55 }
 56 
 57 inline void out() {
 58     for(int i = 0; i <= m; i++) {
 59         printf("%d", now[i]);
 60     }
 61     return;
 62 }
 63 
 64 inline int get2(int p) {
 65     int cnt = 0;
 66     while(1) {
 67         //printf("get 2 \n");
 68         if(now[p] == 2 && !cnt) {
 69             return p;
 70         }
 71         if(now[p] == 1) {
 72             cnt++;
 73         }
 74         else if(now[p] == 2) {
 75             cnt--;
 76         }
 77         p++;
 78     }
 79 }
 80 
 81 inline int get1(int p) {
 82     int cnt = 0;
 83     while(1) {
 84         //printf("get 1 \n");
 85         if(now[p] == 1 && !cnt) {
 86             return p;
 87         }
 88         if(now[p] == 2) {
 89             cnt++;
 90         }
 91         else if(now[p] == 1) {
 92             cnt--;
 93         }
 94         p--;
 95     }
 96 }
 97 
 98 inline char gc() {
 99     char c = getchar();
100     while(c != '*' && c != '.') c = getchar();
101     return c;
102 }
103 
104 int main() {
105 
106     //printf("%d", sizeof(f) / 1048576);
107     //freopen("in.in", "r", stdin);
108     //freopen("my.out", "w", stdout);
109 
110     scanf("%d%d", &n, &m);
111     for(int i = 0; i < n; i++) {
112         for(int j = 0; j < m; j++) {
113             G[i][j] = (gc() == '*');
114         }
115     }
116 
117     int last_x, last_y;
118     for(int i = n - 1; i >= 0; i--) {
119         for(int j = m - 1; j >= 0; j--) {
120             if(!G[i][j]) {
121                 last_x = i;
122                 last_y = j;
123                 i = -1;
124                 break;
125             }
126         }
127     }
128 
129     prework();
130 
131     int lm = pow(3, m + 1), flag = 1;
132     LL ans = 0;
133     f[0][id[0]] = 1;
134     for(int i = 0; i < n; i++) {
135         for(int j = 0; j < m; j++) {
136             flag ^= 1;
137             for(int s = 1; s <= top; s++) {
138                 f[flag ^ 1][s] = 0;
139             }
140             //printf("%d %d \n", i, j);
141             for(int s = 1; s <= top; s++) {
142                 if(!f[flag][s]) {
143                     continue;
144                 }
145                 unzip(s, now);
146                 // f[i][j][s] -> f[i][j + 1][?]
147                 /// now[j] now[j + 1]
148                 // DP
149                 LL c = f[flag][s];
150                 //printf(" > > s :"); out(); printf(" %d \n", c);
151                 if(G[i][j]) {
152                     if(!now[j] && !now[j + 1]) {
153                         add(f[flag ^ 1][s], c);
154                     }
155                     continue;
156                 }
157                 if(!now[j] && !now[j + 1]) { /// 0 0
158                     now[j] = 1;
159                     now[j + 1] = 2;
160                     add(f[flag ^ 1][zip(now)], c);
161                     now[j] = now[j + 1] = 0;
162                 }
163                 else if(!now[j] || !now[j + 1]) { /// [0  1/2]  [1/2  0]  hold / swap
164                     add(f[flag ^ 1][s], c);
165                     std::swap(now[j], now[j + 1]);
166                     add(f[flag ^ 1][zip(now)], c);
167                     std::swap(now[j], now[j + 1]);
168                 }
169                 else if(now[j] == 1 && now[j + 1] == 1) { /// 1 1   the first 2 -> 1
170                     int p = get2(j + 2);
171                     now[p] = 1; now[j] = now[j + 1] = 0;
172                     add(f[flag ^ 1][zip(now)], c);
173                     now[p] = 2; now[j] = now[j + 1] = 1;
174                 }
175                 else if(now[j] == 2 && now[j + 1] == 2) { /// 2 2   the first 1 -> 2
176                     int p = get1(j - 1);
177                     now[p] = 2; now[j] = now[j + 1] = 0;
178                     add(f[flag ^ 1][zip(now)], c);
179                     now[1] = 1; now[j] = now[j + 1] = 2;
180                 }
181                 else if(now[j] == 2 && now[j + 1] == 1) { /// 2 1  merge
182                     now[j] = now[j + 1] = 0;
183                     add(f[flag ^ 1][zip(now)], c);
184                     now[j] = 2; now[j + 1] = 1;
185                 }
186                 else if(i == last_x && j == last_y) { /// 1 2  END
187                     bool t = 0;
188                     for(int q = 0; q < j; q++) {
189                         if(now[q]) {
190                             t = 1;
191                             break;
192                         }
193                     }
194                     for(int q = j + 2; q <= m; q++) {
195                         if(now[q]) {
196                             t = 1;
197                             break;
198                         }
199                     }
200                     if(!t) add(ans, c);
201                 }
202             }
203         }
204         if(i < n - 1) {
205             // change row
206             for(int s = top; s >= 1; s--) {
207                 if(state[s] % 3) {
208                     f[flag ^ 1][s] = 0;
209                 }
210                 else {
211                     f[flag ^ 1][s] = f[flag ^ 1][id[state[s] / 3]];
212                 }
213             }
214         }
215     }
216 
217     printf("%lld\n", ans);
218     return 0;
219 }
AC代码

例题:hdu1693  不用记录左/右插头,直接DP,随意转移。

  1 #include <cstdio>
  2 #include <cstring>
  3 
  4 typedef long long LL;
  5 const int N = 13;
  6 
  7 int G[N][N], m, n;
  8 LL f[2][1480010];
  9 
 10 inline void add(LL &a, LL b) {
 11     a += b;
 12     return;
 13 }
 14 
 15 inline void out(int x) {
 16     printf("%d ", x);
 17     for(int i = 0; i <= m; i++) {
 18         printf("%d", (x >> i) & 1);
 19     }
 20     return;
 21 }
 22 
 23 /*
 24 2
 25 2 4
 26 1 1 1 1
 27 1 1 1 1
 28 */
 29 
 30 inline LL solve() {
 31     memset(f, 0, sizeof(f));
 32     scanf("%d%d", &n, &m);
 33     int last_x, last_y;
 34     for(int i = 0; i < n; i++) {
 35         for(int j = 0; j < m; j++) {
 36             scanf("%d", &G[i][j]);
 37             if(G[i][j]) {
 38                 last_x = i;
 39                 last_y = j;
 40             }
 41             G[i][j] ^= 1;
 42         }
 43     }
 44 
 45     int lm = 1 << (m + 1), flag = 1;
 46     LL ans = 0;
 47     f[0][0] = 1;
 48     for(int i = 0; i < n; i++) {
 49         for(int j = 0; j < m; j++) {
 50             flag ^= 1;
 51             //printf("%d %d \n", i, j);
 52             for(int s = 0; s < lm; s++) {
 53                 f[flag ^ 1][s] = 0;
 54             }
 55             for(int s = 0; s < lm; s++) {
 56                 //printf("f %d %d = %d \n", flag, s, f[flag][s]);
 57                 if(!f[flag][s]) {
 58                     continue;
 59                 }
 60                 int a = (s >> j) & 1, b = (s >> (j + 1)) & 1;
 61                 LL c = f[flag][s];
 62                 //printf(" > s : "); out(s); printf(" = %d \n", c);
 63                 if(G[i][j]) {
 64                     if(!a && !b) {
 65                         add(f[flag ^ 1][s], c);
 66                     }
 67                 }
 68                 else if(!a && !b) { /// 0 0
 69                     add(f[flag ^ 1][s | (1 << j) | (1 << (j + 1))], c);
 70                     //printf(" ---> %d %d \n", flag ^ 1, s | (1 << j) | (1 << (j + 1)));
 71                 }
 72                 else if(a && b) {
 73                     add(f[flag ^ 1][s & (~((1 << j) | (1 << (j + 1))))], c);
 74                 }
 75                 else if(a) {
 76                     add(f[flag ^ 1][s], c);
 77                     add(f[flag ^ 1][(s | (1 << (j + 1))) & (~(1 << j))], c);
 78                 }
 79                 else if(b) {
 80                     add(f[flag ^ 1][s], c);
 81                     add(f[flag ^ 1][(s | (1 << j)) & (~(1 << (j + 1)))], c);
 82                 }
 83             }
 84             if(i == last_x && j == last_y) {
 85                 return f[flag ^ 1][0];
 86             }
 87         }
 88         /// line i -> i + 1
 89         for(int s = lm - 1; s >= 0; s--) {
 90             if(s & 1) {
 91                 f[flag ^ 1][s] = 0;
 92             }
 93             else {
 94                 f[flag ^ 1][s] = f[flag ^ 1][s >> 1];
 95             }
 96         }
 97     }
 98     return -1;
 99 }
100 
101 int main() {
102     int T;
103     scanf("%d", &T);
104     for(int i = 1; i <= T; i++) {
105         LL ans = solve();
106         printf("Case %d: There are %lld ways to eat the trees.\n", i, ans);
107         //printf("%lld \n", ans);
108     }
109     return 0;
110 }
AC代码

例题:poj3133 求把网格图上2和3连通起来的最小格子数。

求最值,一样的套路...

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <algorithm>
  5 
  6 const int N = 15, INF = 0x3f3f3f3f;
  7 
  8 int G[N][N], now[N], m, n;
  9 int f[2][60010];
 10 
 11 inline int zip(int *a) {
 12     int ans = 0;
 13     for(int i = m; i >= 0; i--) {
 14         ans = ans * 3 + a[i];
 15     }
 16     return ans;
 17 }
 18 
 19 inline void unzip(int x, int *a) {
 20     for(int i = 0; i <= m; i++) {
 21         a[i] = x % 3;
 22         x /= 3;
 23     }
 24     return;
 25 }
 26 
 27 inline void out() {
 28     for(int i = 0; i <= m; i++) {
 29         printf("%d", now[i]);
 30     }
 31     return;
 32 }
 33 
 34 inline void exmin(int &x, int y) {
 35     x > y ? x = y : 0;
 36     return;
 37 }
 38 
 39 inline void solve() {
 40     memset(f, 0x3f, sizeof(f));
 41     int last_x, last_y;
 42     for(int i = 0; i < n; i++) {
 43         for(int j = 0; j < m; j++) {
 44             scanf("%d", &G[i][j]);
 45             if(G[i][j] != 1) {
 46                 last_x = i;
 47                 last_y = j;
 48             }
 49             if(G[i][j] == 1 || G[i][j] == 3) {
 50                 G[i][j] = 4 - G[i][j];
 51             }
 52         }
 53     }
 54 
 55     int flag = 1, lm = pow(3, m + 1);
 56     f[0][0] = 0;
 57     for(int i = 0; i < n; i++) {
 58         for(int j = 0; j < m; j++) {
 59             flag ^= 1;
 60             for(int s = 0; s < lm; s++) {
 61                 f[flag ^ 1][s] = INF;
 62             }
 63             //printf("%d %d \n", i, j);
 64             for(int s = 0; s < lm; s++) {
 65                 if(f[flag][s] == INF) {
 66                     continue;
 67                 }
 68                 unzip(s, now);
 69                 int c = f[flag][s], &a = now[j], &b = now[j + 1];
 70 
 71                 //printf("   "); out(); printf(" = %d \n", c);
 72 
 73                 if(G[i][j] == 3) {
 74                     if(!a && !b) {
 75                         exmin(f[flag ^ 1][s], c);
 76                     }
 77                 }
 78                 else if(G[i][j] == 1) {
 79                     if(a == 1 && !b) {
 80                         a = 0;
 81                         exmin(f[flag ^ 1][zip(now)], c + 1);
 82                         a = 1;
 83                     }
 84                     else if(b == 1 && !a) {
 85                         b = 0;
 86                         exmin(f[flag ^ 1][zip(now)], c + 1);
 87                         b = 1;
 88                     }
 89                     else if(!a && !b) {
 90                         a = 1;
 91                         exmin(f[flag ^ 1][zip(now)], c + 1);
 92                         a = 0;
 93                         b = 1;
 94                         exmin(f[flag ^ 1][zip(now)], c + 1);
 95                         b = 0;
 96                     }
 97                 }
 98                 else if(G[i][j] == 2) {
 99                     if(a == 2 && !b) {
100                         a = 0;
101                         exmin(f[flag ^ 1][zip(now)], c + 1);
102                         a = 2;
103                     }
104                     else if(b == 2 && !a) {
105                         b = 0;
106                         exmin(f[flag ^ 1][zip(now)], c + 1);
107                         b = 2;
108                     }
109                     else if(!a && !b) {
110                         a = 2;
111                         exmin(f[flag ^ 1][zip(now)], c + 1);
112                         a = 0;
113                         b = 2;
114                         exmin(f[flag ^ 1][zip(now)], c + 1);
115                         b = 0;
116                     }
117                 } /// G[i][j] == 0
118                 else if(!a && !b) { /// 0 0
119                     exmin(f[flag ^ 1][s], c); // not choose
120                     a = b = 1;
121                     exmin(f[flag ^ 1][zip(now)], c + 1); // choose 1
122                     a = b = 2;
123                     exmin(f[flag ^ 1][zip(now)], c + 1); // choose 2
124                     a = b = 0;
125                 }
126                 else if(b == 1 && a == 1) { /// 1 1 merge
127                     a = b = 0;
128                     exmin(f[flag ^ 1][zip(now)], c + 1);
129                     a = b = 1;
130                 }
131                 else if(a == 2 && b == 2) { /// 2 2 merge
132                     a = b = 0;
133                     exmin(f[flag ^ 1][zip(now)], c + 1);
134                     a = b = 2;
135                 }
136                 else if(a == 0 || b == 0) { /// a=0 / b=0  swap
137                     exmin(f[flag ^ 1][s], c + 1);
138                     std::swap(a, b);
139                     exmin(f[flag ^ 1][zip(now)], c + 1);
140                     std::swap(a, b);
141                 }
142             }
143             if(i == last_x && j == last_y) {
144                 if(f[flag ^ 1][0] == INF) puts("0");
145                 else printf("%d\n", f[flag ^ 1][0] - 2);
146                 return;
147             }
148         }
149         for(int s = lm - 1; s >= 0; s--) {
150             if(s % 3) {
151                 f[flag ^ 1][s] = INF;
152             }
153             else {
154                 f[flag ^ 1][s] = f[flag ^ 1][s / 3];
155             }
156         }
157     }
158 
159     return;
160 }
161 
162 int main() {
163     scanf("%d%d", &n, &m);
164     while(n) {
165         solve();
166         scanf("%d%d", &n, &m);
167     }
168     return 0;
169 }
AC代码

 

posted @ 2019-02-23 17:23  huyufeifei  阅读(...)  评论(...编辑  收藏