插头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代码

猜你喜欢

转载自www.cnblogs.com/huyufeifei/p/10423472.html