【插头DP】ZOJ 3213

通道:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3396

题意:简单路径,任意起点终点,权值和最大,有阻碍点。

思路:起点终点不固定,加个单插头就好了,妈蛋,单插头问题用括号匹配法搞了很久,并不对。。。too young too naive;

代码:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #define MAXD 15
  4 #define HASH 30007
  5 #define SIZE 1000010
  6 int N, M, maze[MAXD][MAXD], code[MAXD], ch[MAXD], num, ans;
  7 struct Hashmap
  8 {
  9     int head[HASH], next[SIZE], state[SIZE], f[SIZE], size;
 10     void init()
 11     {
 12         memset(head, -1, sizeof(head));
 13         size = 0;
 14     }
 15     void push(int st, int ans)
 16     {
 17         int i, h = st % HASH;
 18         for(i = head[h]; i != -1; i = next[i])
 19             if(st == state[i])
 20             {
 21                 if(ans > f[i])
 22                     f[i] = ans;
 23                 return ;
 24             }
 25         state[size] = st, f[size] = ans;
 26         next[size] = head[h];
 27         head[h] = size ++;
 28     }
 29 }hm[2];
 30 void decode(int *code, int m, int st)
 31 {
 32     int i;
 33     num = st & 7;
 34     for(i = m; i >= 0; i --)
 35     {
 36         st >>= 3;
 37         code[i] = st & 7;
 38     }
 39 }
 40 int encode(int *code, int m)
 41 {
 42     int i, cnt = 1, st = 0;
 43     memset(ch, -1, sizeof(ch));
 44     ch[0] = 0;
 45     for(i = 0; i <= m; i ++)
 46     {
 47         if(ch[code[i]] == -1)
 48             ch[code[i]] = cnt ++;
 49         code[i] = ch[code[i]];
 50         st <<= 3;
 51         st |= code[i];
 52     }
 53     st <<= 3;
 54     st |= num;
 55     return st;
 56 }
 57 void init()
 58 {
 59     int i, j;
 60     scanf("%d%d", &N, &M);
 61     ans = 0;
 62     memset(maze, 0, sizeof(maze));
 63     for(i = 1; i <= N; i ++)
 64         for(j = 1; j <= M; j ++)
 65         {
 66             scanf("%d", &maze[i][j]);
 67             if(maze[i][j] > ans)
 68                 ans = maze[i][j];
 69         }
 70 }
 71 void dpblank(int i, int j, int cur)
 72 {
 73     int k, left, up, t;
 74     for(k = 0; k < hm[cur].size; k ++)
 75     {
 76         decode(code, M, hm[cur].state[k]);
 77         left = code[j - 1], up = code[j];
 78         if(left && up)
 79         {
 80             if(left != up)
 81             {
 82                 code[j - 1] = code[j] = 0;
 83                 for(t = 0; t <= M; t ++)
 84                     if(code[t] == up)
 85                         code[t] = left;
 86                 hm[cur ^ 1].push(encode(code, j == M ? M - 1 : M), hm[cur].f[k] + maze[i][j]);
 87             }
 88         }
 89         else if(left || up)
 90         {
 91             if(maze[i][j + 1])
 92             {
 93                 code[j - 1] = 0, code[j] = left + up;
 94                 hm[cur ^ 1].push(encode(code, M), hm[cur].f[k] + maze[i][j]);
 95             }
 96             if(maze[i + 1][j])
 97             {
 98                 code[j - 1] = left + up, code[j] = 0;
 99                 hm[cur ^ 1].push(encode(code, j == M ? M - 1 : M), hm[cur].f[k] + maze[i][j]);
100             }
101             if(num < 2)
102             {
103                 ++ num, code[j - 1] = code[j] = 0;
104                 hm[cur ^ 1].push(encode(code, j == M ? M - 1 : M), hm[cur].f[k] + maze[i][j]);
105             }
106         }
107         else
108         {
109             code[j - 1] = code[j] = 0;
110             hm[cur ^ 1].push(encode(code, j == M ? M - 1 : M), hm[cur].f[k]);
111             if(maze[i][j + 1] && maze[i + 1][j])
112             {
113                 code[j - 1] = code[j] = 13;
114                 hm[cur ^ 1].push(encode(code, M), hm[cur].f[k] + maze[i][j]);
115             }
116             if(num < 2)
117             {
118                 ++ num;
119                 if(maze[i + 1][j])
120                 {
121                     code[j - 1] = 13, code[j] = 0;
122                     hm[cur ^ 1].push(encode(code, j == M ? M - 1 : M), hm[cur].f[k] + maze[i][j]);
123                 }
124                 if(maze[i][j + 1])
125                 {
126                     code[j - 1] = 0, code[j] = 13;
127                     hm[cur ^ 1].push(encode(code, M), hm[cur].f[k] + maze[i][j]);
128                 }
129             }
130         }
131     }
132 }
133 void dpblock(int i, int j, int cur)
134 {
135     int k;
136     for(k = 0; k < hm[cur].size; k ++)
137     {
138         decode(code, M, hm[cur].state[k]);
139         code[j - 1] = code[j] = 0;
140         hm[cur ^ 1].push(encode(code, j == M ? M - 1 : M), hm[cur].f[k]);
141     }
142 }
143 void solve()
144 {
145     int i, j, cur = 0;
146     hm[cur].init();
147     hm[cur].push(0, 0);
148     for(i = 1; i <= N; i ++)
149         for(j = 1; j <= M; j ++)
150         {
151             hm[cur ^ 1].init();
152             if(maze[i][j])
153                 dpblank(i, j, cur);
154             else
155                 dpblock(i, j, cur);
156             cur ^= 1;
157         }
158     for(i = 0; i < hm[cur].size; i ++)
159         if(hm[cur].f[i] > ans)
160             ans = hm[cur].f[i];
161     printf("%d\n", ans);
162 }
163 int main() {
164     int t;
165     scanf("%d", &t);
166     while(t --)
167     {
168         init();
169         solve();
170     }
171     return 0;
172 }
173
174 /*
175 41
176 14
177 28
178 19
179 41
180 26
181 10
182 12
183 29
184 74
185 66
186 91
187 192
188 338
189
190 */
191
192 /*
193
194 100
195
196 4 4
197 5 1 1 4
198 0 0 7 7
199 4 0 1 8
200 1 2 4 0
201
202 6 5
203 1 1 1 1 0
204 1 0 0 1 0
205 1 0 1 1 0
206 1 0 1 0 0
207 1 1 1 0 0
208 0 0 0 0 0
209
210 3 4
211 8 7 0 7
212 0 0 8 2
213 0 0 7 4
214
215 2 4
216 8 0 1 0
217 4 5 1 0
218
219 4 4
220 1 8 0 4
221 2 1 7 0
222 4 8 2 0
223 2 0 7 1
224
225 3 4
226 4 5 0 1
227 5 1 0 7
228 4 7 0 0
229
230 3 2
231 8 2
232 0 0
233 1 0
234
235 3 4
236 0 0 1 1
237 7 0 4 2
238 1 4 0 0
239
240 4 2
241 7 7
242 0 1
243 7 7
244 0 5
245
246 3 3
247 42 0 35
248 0 0 29
249 41 33 0
250
251
252 2 2
253 49 0
254 7 10
255
256 3 2
257 0 39
258 37 15
259 0 35
260
261 3 3
262 0 49 19
263 17 0 13
264 41 29 24
265
266 3 7
267 0 16 0 11 34 38 0
268 29 48 0 0 0 12 7
269 46 39 9 12 23 2 12
270
271
272 */

附上括号匹配法(未AC):

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4
  5 using namespace std;
  6
  7 const int MAX_N = 15;
  8 const int MAX_M = 15;
  9 const int HASH = 100007;
 10 const int MAX_S = 1000007;
 11
 12 struct node {
 13     int head[HASH], nxt[MAX_S], dp[MAX_S], st[MAX_S];
 14     int cnt, num[MAX_S];
 15     void cr() {
 16         memset(head, -1, sizeof head);
 17         cnt = 0;
 18     }
 19     void push(int s, int v, int val) {
 20         int now = s % HASH;
 21         for(int i = head[now]; ~i; i = nxt[i]) {
 22             int p = st[i];
 23             if(p == s && num[i] == val) {
 24                 dp[i] = max(dp[i], v);
 25                 return;
 26             }
 27         }
 28         st[cnt] = s;
 29         dp[cnt] = v; num[cnt] = val;
 30         nxt[cnt] = head[now];
 31         head[now] = cnt++;
 32         return;
 33     }
 34 }d[2];
 35
 36 int n, m;
 37 int a[MAX_N][MAX_M];
 38
 39 int find_pos(int s, int p) {
 40     return (s >> (p << 1)) & 3;
 41 }
 42
 43 void tp(int &s, int p, int v) {
 44     s &= (~(3 << (p << 1)));
 45     s |= (v << (p << 1));
 46 }
 47
 48 int find_r(int s, int p) {
 49     int cnt = 0;
 50     for(int i = p; i <= m; ++i) {
 51         if(find_pos(s, i) == 1) ++cnt;
 52         else if(find_pos(s, i) == 2) --cnt;
 53         if(!cnt) return i;
 54     }
 55     return p;
 56 }
 57
 58 int find_l(int s, int p) {
 59     int cnt = 0;
 60     for(int i = p; i >= 0; --i) {
 61         if(find_pos(s, i) == 2) ++cnt;
 62         else if(find_pos(s, i) == 1) --cnt;
 63         if(!cnt) return i;
 64     }
 65     return p;
 66 }
 67 int ans;
 68 void blank(int i, int j, int cur) {
 69     for(int k = 0; k < d[cur].cnt; ++k) {
 70         int t = d[cur].st[k];
 71         int l = find_pos(t, j - 1), r = find_pos(t, j);
 72         int sum = 0;
 73         for (int z = 0; z <= m; ++z) if (find_pos(t, z)) ++sum;
 74         if (d[cur].num[k] + sum <= 2) ans = max(ans, d[cur].dp[k]);
 75        if (d[cur].num[k] == 2 && sum == 0) continue;
 76        // if (i == 4 && j == 3 && d[cur].dp[k] == 37) printf("qa %d %d %d %d %d\n", l, r, d[cur].st[k], d[cur].dp[k], d[cur].num[k]);
 77         if(l && r) {
 78             if(l == 1 && r == 1) {
 79                 int tpos = find_r(t, j); //if (i == 2 && j == 3) printf("here %d %d %d %d\n", t, tpos, find_pos(t, 3), find_pos(t, 4));
 80                 tp(t, j - 1, 0); tp(t, j, 0); if (tpos != j) tp(t, tpos, 1);
 81                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k]);
 82             } else if(l == 2 && r == 1) {
 83                 tp(t, j - 1, 0); tp(t, j, 0);
 84                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k]);
 85             } else if(l == 2 && r == 2) {
 86                 int tpos = find_l(t, j - 1);
 87                 tp(t, j - 1, 0); tp(t, j, 0); if (tpos != j - 1) tp(t, tpos, 2);
 88                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k]);
 89             } else { // 最后一个非障碍格子
 90
 91                 if (j < m) {
 92                     tp(t, j - 1, 0), tp(t, j, 1);
 93                     d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k]);
 94                 }
 95                 if (i < n) {
 96                     t = d[cur].st[k];
 97                     tp(t, j - 1, 2), tp(t, j, 0);
 98                     d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k]);
 99                 }
100                 if (i == n && j == m) {
101                     tp(t, j - 1, 0); tp(t, j, 0);
102                     // here
103                     d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k]);
104                 }
105
106             }
107         } else if(l) {
108             if(i < n) {
109                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k]);
110             }
111             if(j < m) {
112                 tp(t, j - 1, 0); tp(t, j, l);
113                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k]);
114             }
115             if (d[cur].num[k] < 2) {
116                 t = d[cur].st[k];
117                 tp(t, j - 1, 0); tp(t, j, 0);
118                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k] + 1);
119             }
120         } else if(r) {
121             if(j < m) {
122                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k]);
123             }
124             if(i < n) {
125                 tp(t, j - 1, r); tp(t, j, 0);
126                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k]);
127             }
128             if (d[cur].num[k] < 2) {
129                 t = d[cur].st[k];
130                 tp(t, j - 1, 0); tp(t, j, 0);
131                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k] + 1);
132             }
133         } else { // 新建
134             d[cur ^ 1].push(t, d[cur].dp[k], d[cur].num[k]);
135             if(i < n && j < m && a[i + 1][j] && a[i][j + 1]) {
136                 tp(t, j - 1, 1); tp(t, j, 2);
137                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k]);
138             }
139             if (d[cur].num[k] < 2) {
140                 if (i < n && a[i + 1][j]) {
141                     t = d[cur].st[k];
142                     tp(t, j - 1, 1); tp(t, j, 0);
143                     d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k] + 1);
144                 }
145                 if (j < m && a[i][j + 1]) {
146                     t = d[cur].st[k];
147                     tp(t, j - 1, 0); tp(t, j, 2);
148                     d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j], d[cur].num[k] + 1);
149                 }
150             }
151         }
152     }
153 }
154
155 void block(int i, int j, int cur) {
156     for (int k = 0; k < d[cur].cnt; ++k) {
157         long long t = d[cur].st[k];
158         int l = find_pos(t, j - 1), r = find_pos(t, j);  //if (i == 3 && j == 3) printf("%d %d %d %d %d\n", l, r, d[cur].st[k], d[cur].dp[k], d[cur].num[k]);
159         if (!l && !r) d[cur ^ 1].push(t, d[cur].dp[k], d[cur].num[k]);
160     }
161 }
162
163
164 int main() {
165     int T;
166     scanf("%d", &T);
167     while (T-- > 0) {
168         scanf("%d%d", &n, &m);
169         memset(a, 0, sizeof a);
170         memset(d[0].num, 0, sizeof d[0].num);
171         memset(d[1].num, 0, sizeof d[1].num);
172         memset(d[0].dp, 0, sizeof d[0].dp);
173         memset(d[1].dp, 0, sizeof d[1].dp);
174             ans = 0;
175         for(int i = 1; i <= n; i ++) {
176             for(int j = 1; j <= m; j ++) {
177                 scanf("%d", &a[i][j]);
178                 ans = max(ans, a[i][j]);
179             }
180         }
181         int cur = 0;
182         d[cur].cr();
183         d[cur].push(0, 0, 0);
184         for(int i = 1; i <= n; i ++) {
185             for(int j = 1; j <= m; j ++) {
186                 d[cur ^ 1].cr();
187                 if (a[i][j]) blank(i, j, cur);
188                 else block(i, j, cur);
189                 cur ^= 1;
190             }
191             for(int k = 0; k < d[cur].cnt; ++k) {
192                 d[cur].st[k] <<= 2;
193             }
194         }
195         //for (int i = 0; i < d[cur].cnt; ++i) printf("%d %d\n", d[cur].st[i], d[cur].dp[i]);
196         for (int i = 0; i < d[cur].cnt; ++i) //if (d[cur].num[i] == 2)
197             ans = max(ans, d[cur].dp[i]);
198         printf("%d\n", ans);
199     }
200     return 0;
201 }
202
203 /*
204 41
205 14
206 28
207 19
208 41
209 26
210 10
211 12
212 29
213 74
214 66
215 91
216 192
217 338
218
219 */
220
221 /*
222
223 100
224
225 4 4
226 5 1 1 4
227 0 0 7 7
228 4 0 1 8
229 1 2 4 0
230
231 6 5
232 1 1 1 1 0
233 1 0 0 1 0
234 1 0 1 1 0
235 1 0 1 0 0
236 1 1 1 0 0
237 0 0 0 0 0
238
239 3 4
240 8 7 0 7
241 0 0 8 2
242 0 0 7 4
243
244 2 4
245 8 0 1 0
246 4 5 1 0
247
248 4 4
249 1 8 0 4
250 2 1 7 0
251 4 8 2 0
252 2 0 7 1
253
254 3 4
255 4 5 0 1
256 5 1 0 7
257 4 7 0 0
258
259 3 2
260 8 2
261 0 0
262 1 0
263
264 3 4
265 0 0 1 1
266 7 0 4 2
267 1 4 0 0
268
269 4 2
270 7 7
271 0 1
272 7 7
273 0 5
274
275 3 3
276 42 0 35
277 0 0 29
278 41 33 0
279
280
281 2 2
282 49 0
283 7 10
284
285 3 2
286 0 39
287 37 15
288 0 35
289
290 3 3
291 0 49 19
292 17 0 13
293 41 29 24
294
295 3 7
296 0 16 0 11 34 38 0
297 29 48 0 0 0 12 7
298 46 39 9 12 23 2 12
299
300
301 */

时间: 2024-08-04 10:36:39

【插头DP】ZOJ 3213的相关文章

插头dp的几个模板

/* ural1519 求经过全部可行点的哈密顿回路的个数 括号匹配法,转移有点复杂,可是时间空间比較小 */ #include<cstdio> #include<cstring> #include<string> #include<iostream> #include<algorithm> #include<cmath> #include<map> #include<queue> #define LL lon

ZOJ 3213

1 /* 2 ZOJ 3213 3 4 好吧,看过那种括号表示法后,就崩溃了,实在受不了.情况复杂,写了两天,人也有点傻X了,只能放弃,转而用最小表示法. 5 最小表示法不难写: 6 7 1)首先,要承认路径上有格子不选的情况,于是,在00的情况下,可扩展,也可不选. 8 2)不能出现环,因而不能有L=U的情况出现. 9 3)以下是模版代码,类同是必然.但转而求路径数的时候,应当去掉不扩展的情况,同时,在IF(L|U)的情况下,亦不必考虑当前是否为最后一个格子, 10 只需按写的转移即可. 11

插头DP专题

建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议先理解“插头”的概念.然后会HASH表(这个其实是很基础的东西,应该都会的).然后就是DP. 以及特殊题目的特殊处理. 好像一般是求N,M<=12的网格图的某种回路数或某种通路数的方案数. 大体上每个题说几句特殊处理,有问题请纠正....题目的顺序基本上难度递增 另外代码我都是用括号匹配的.因为感觉连通

插头DP小结

首先是CDQ<基于连通性状态压缩的动态规划问题>论文上的题目: URAL 1519 Formula 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int maxn = 15; 6 const int HASH = 30007; 7 const int SIZE = 1000010; 8 typedef long lon

插头dp

对于网格中的dp可以用轮廓线,如果有一些格子不能走就可以用插头dp了. bzoj2331 地板 题目大意:用L型铺地n*m,有一些格子不能铺,求方案数. 思路:fi[i][j][s]表示铺到(i,j),轮廓线状态s,0表示没有插头,1表示插头没拐弯,2表示插头拐弯了,手动枚举转移. 注意:(1)按四进制好写: (2)因为实际状态和四进制的差很多,所以用hash表来存储,防止mle和tle,同时使用滚动数组. #include<iostream> #include<cstdio> #

[入门向选讲] 插头DP:从零概念到入门 (例题:HDU1693 COGS1283 BZOJ2310 BZOJ2331)

转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7326874.html 最近搞了一下插头DP的基础知识……这真的是一种很锻炼人的题型…… 每一道题的状态都不一样,并且有不少的分类讨论,让插头DP十分锻炼思维的全面性和严谨性. 下面我们一起来学习插头DP的内容吧! 插头DP主要用来处理一系列基于连通性状态压缩的动态规划问题,处理的具体问题有很多种,并且一般数据规模较小. 由于棋盘有很特殊的结构,使得它可以与“连通性”有很强的联系,因此插头DP最常见的应用要数

插头DP学习

队内没人会插头DP,感觉这个不会不行...所以我还是默默去学了一下, 学了一天,感觉会了一点.对于每一行,一共有j+1个插头,如果是多回路类的题目, 比较简单,可以用1表示有插头,0表示没有插头,这样就可以愉快转移了, 对于当前出来的位置(i,j),与它有关的插头有j-1和j 那么我们可以枚举状态经行转移. 对于单回路的问题....只是了解思想,目前还不会写,太笨了=_= poj 2411 Mondriaan's Dream 题意:用1*2小方块组成n*m矩阵有多少种组成方式 思路:我们从上到下

BZOJ 2595 游览计划(插头DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2595 题意:给出一个数字矩阵.求一个连通块包含所有的数字0且连通块内所有数字之和最小. 思路:对于每个格子,是0则必须要选.那么对于不选的格子(i,j)在什么时候可以不选呢?必须同时满足以下两个条件: (1)(i,j)不是0: (2)(i-1,j)不选或者(i-1,j)选了但是轮廓线上还有别的地方与(i-1,j)是一个连通块. int Pre[105][N],op[105][N]; s

【插头dp】CDOJ1690 这是一道比CCCC简单题难的简单题

最裸的插头dp,可参见大白书. #include<cstdio> #include<cstring> using namespace std; #define MOD 1000000007 int f[2][(1<<5)+10],n,m; int main(){ scanf("%d%d",&n,&m); int cur=0; f[0][(1<<m)-1]=1; for(int i=0;i<n;++i){ for(in

POJ 2411 Mondriaan&#39;s Dream ——状压DP 插头DP

[题目分析] 用1*2的牌铺满n*m的格子. 刚开始用到动规想写一个n*m*2^m,写了半天才知道会有重复的情况. So Sad. 然后想到数据范围这么小,爆搜好了.于是把每一种状态对应的转移都搜了出来. 加了点优(gou)化(pi),然后poj上1244ms垫底. 大概的方法就是考虑每一层横着放的情况,剩下的必须竖起来的情况到下一层取反即可. 然后看了 <插头DP-从入门到跳楼> 这篇博客,怒抄插头DP 然后16ms了,自己慢慢YY了一下,写出了风(gou)流(pi)倜(bu)傥(tong)