ZOJ_3213
我是用最小表示法写的这个插头dp,相比于回路问题来讲,变简单的地方是不用考虑合并两个相同的连通分量这一情况了,变复杂的地方就是多出了两个个独立插头。
为了搞定独立插头的问题,我在编码的时候额外加了一个状态num,表示当前已经使用的独立插头的数目,这样只要保证num不超过2而且不合并相同的连通分量就能保证最后是一条简单路径。
在dp的时候因为多了独立插头,所以分的情况就更多一些。
#include<stdio.h> #include<string.h> #define MAXD 15 #define HASH 30007 #define SIZE 1000010 int N, M, maze[MAXD][MAXD], code[MAXD], ch[MAXD], num, ans; struct Hashmap { int head[HASH], next[SIZE], state[SIZE], f[SIZE], size; void init() { memset(head, -1, sizeof(head)); size = 0; } void push(int st, int ans) { int i, h = st % HASH; for(i = head[h]; i != -1; i = next[i]) if(st == state[i]) { if(ans > f[i]) f[i] = ans; return ; } state[size] = st, f[size] = ans; next[size] = head[h]; head[h] = size ++; } }hm[2]; void decode(int *code, int m, int st) { int i; num = st & 7; for(i = m; i >= 0; i --) { st >>= 3; code[i] = st & 7; } } int encode(int *code, int m) { int i, cnt = 1, st = 0; memset(ch, -1, sizeof(ch)); ch[0] = 0; for(i = 0; i <= m; i ++) { if(ch[code[i]] == -1) ch[code[i]] = cnt ++; code[i] = ch[code[i]]; st <<= 3; st |= code[i]; } st <<= 3; st |= num; return st; } void init() { int i, j; scanf("%d%d", &N, &M); ans = 0; memset(maze, 0, sizeof(maze)); for(i = 1; i <= N; i ++) for(j = 1; j <= M; j ++) { scanf("%d", &maze[i][j]); if(maze[i][j] > ans) ans = maze[i][j]; } } void dpblank(int i, int j, int cur) { int k, left, up, t; for(k = 0; k < hm[cur].size; k ++) { decode(code, M, hm[cur].state[k]); left = code[j - 1], up = code[j]; if(left && up) { if(left != up) { code[j - 1] = code[j] = 0; for(t = 0; t <= M; t ++) if(code[t] == up) code[t] = left; hm[cur ^ 1].push(encode(code, j == M ? M - 1 : M), hm[cur].f[k] + maze[i][j]); } } else if(left || up) { if(maze[i][j + 1]) { code[j - 1] = 0, code[j] = left + up; hm[cur ^ 1].push(encode(code, M), hm[cur].f[k] + maze[i][j]); } if(maze[i + 1][j]) { code[j - 1] = left + up, code[j] = 0; hm[cur ^ 1].push(encode(code, j == M ? M - 1 : M), hm[cur].f[k] + maze[i][j]); } if(num < 2) { ++ num, code[j - 1] = code[j] = 0; hm[cur ^ 1].push(encode(code, j == M ? M - 1 : M), hm[cur].f[k] + maze[i][j]); } } else { code[j - 1] = code[j] = 0; hm[cur ^ 1].push(encode(code, j == M ? M - 1 : M), hm[cur].f[k]); if(maze[i][j + 1] && maze[i + 1][j]) { code[j - 1] = code[j] = 13; hm[cur ^ 1].push(encode(code, M), hm[cur].f[k] + maze[i][j]); } if(num < 2) { ++ num; if(maze[i + 1][j]) { code[j - 1] = 13, code[j] = 0; hm[cur ^ 1].push(encode(code, j == M ? M - 1 : M), hm[cur].f[k] + maze[i][j]); } if(maze[i][j + 1]) { code[j - 1] = 0, code[j] = 13; hm[cur ^ 1].push(encode(code, M), hm[cur].f[k] + maze[i][j]); } } } } } void dpblock(int i, int j, int cur) { int k; for(k = 0; k < hm[cur].size; k ++) { decode(code, M, hm[cur].state[k]); code[j - 1] = code[j] = 0; hm[cur ^ 1].push(encode(code, j == M ? M - 1 : M), hm[cur].f[k]); } } void solve() { int i, j, cur = 0; hm[cur].init(); hm[cur].push(0, 0); for(i = 1; i <= N; i ++) for(j = 1; j <= M; j ++) { hm[cur ^ 1].init(); if(maze[i][j]) dpblank(i, j, cur); else dpblock(i, j, cur); cur ^= 1; } for(i = 0; i < hm[cur].size; i ++) if(hm[cur].f[i] > ans) ans = hm[cur].f[i]; printf("%d\n", ans); } int main() { int t; scanf("%d", &t); while(t --) { init(); solve(); } return 0; }