【插头DP】HDU 4113 Construct the Great Wall
通道:http://acm.hdu.edu.cn/showproblem.php?pid=4113
题意:简单回路,绕着格子轮廓把‘O’围起来,使得里面没有‘X’的最短路径,可选可不选。
思路:首先把格点看成方格,然后行列分别增一。对于区分‘O’和‘X’不能在同一个块里面的处理方法就是状态增加一维,表示该方框的左上角格点是否在内部。
然后状态转移的时候都要预判一下该块的几个是否都在同一块里面,如果不在的话,就要判断左和上和当前格是否在同一个联通块里面
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int MAX_N = 13; 8 const int MAX_M = 13; 9 const int HASH = 10007; 10 const int MAX_S = 1000007; 11 12 const int mov[20] = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30}; 13 14 struct node { 15 int head[HASH], nxt[MAX_S], cnt; 16 long long dp[MAX_S], st[MAX_S]; 17 void init() { 18 memset(head, -1, sizeof head); 19 cnt = 0; 20 } 21 void push(long long s, long long v) { 22 int now = s % HASH; 23 for(int i = head[now]; ~i; i = nxt[i]) if(st[i] == s) { 24 dp[i] = min(dp[i], v); 25 return ; 26 } 27 st[cnt] = s; dp[cnt] = v; 28 nxt[cnt] = head[now]; 29 head[now] = cnt++; 30 } 31 }d[2][2]; 32 33 int n, m; 34 int ex, ey, ans; 35 char a[MAX_N][MAX_M]; 36 37 int find_pos(long long s, int p) { 38 return s >> mov[p] & 3; 39 } 40 41 void tp(long long &s, int p, long long v) { 42 s &= ~(3ll << mov[p]); 43 s |= v << mov[p]; 44 } 45 46 47 int find_r(long long s, int p) { 48 int cnt = 0; 49 for(int i = p; i <= m; ++i) { 50 if(find_pos(s, i) == 1) ++cnt; 51 else if(find_pos(s, i) == 2) --cnt; 52 if(!cnt) return i; 53 } 54 } 55 56 int find_l(long long s, int p) { 57 int cnt = 0; 58 for(int i = p; i >= 0; --i) { 59 if(find_pos(s, i) == 2) ++cnt; 60 else if(find_pos(s, i) == 1) --cnt; 61 if(!cnt) return i; 62 } 63 } 64 65 bool jud(int i, int j, int in) { 66 if(a[i][j] == 'o') return in; 67 if(a[i][j] == 'x') return !in; 68 return true; 69 } 70 71 void blank(int i, int j, int cur, int in) { 72 for(int k = 0; k < d[cur][in].cnt; ++k) { 73 long long t = d[cur][in].st[k]; 74 int l = find_pos(t, j - 1), r = find_pos(t, j); 75 if(l && r) { 76 if(l == 1 && r == 1) { 77 int tpos = find_r(t, j); 78 tp(t, j - 1, 0); tp(t, j, 0); tp(t, tpos, 1); 79 } else if(l == 2 && r == 1) { 80 tp(t, j - 1, 0); tp(t, j, 0); 81 } else if(l == 2 && r == 2) { 82 int tpos = find_l(t, j - 1); 83 tp(t, j - 1, 0); tp(t, j, 0); tp(t, tpos, 2); 84 } else { 85 tp(t, j - 1, 0); tp(t, j, 0); 86 if (i == ex + 1 && j == ey + 1 && !t) 87 ans = min((long long)ans, d[cur][in].dp[k] + 1); 88 continue; 89 } 90 if (jud(i - 1, j, in ^ 1)) d[cur ^ 1][in ^ 1].push(t, d[cur][in].dp[k] + 1);//////////// 91 } else if(l || r) { 92 int in2 = in; 93 if (r) in2 ^= 1;///////////// 94 int tmp = l + r; 95 tp(t, j - 1, tmp), tp(t, j, 0); 96 if (i + 1 <= n && jud(i - 1, j, in2) && jud(i, j - 1, 1 ^ in2) && jud(i, j, in2)) 97 d[cur ^ 1][in2].push(t, d[cur][in].dp[k] + 1); 98 t = d[cur][in].st[k]; 99 tp(t, j - 1, 0), tp(t, j, tmp); 100 if (j + 1 <= m && jud(i - 1, j, in2) && jud(i, j - 1, 1 ^ in2) && jud(i, j, 1 ^ in2)) 101 d[cur ^ 1][in2].push(t, d[cur][in].dp[k] + 1); 102 } else { /////////// 103 if (jud(i - 1, j, in) && jud(i, j - 1, in) && jud(i, j, in)) 104 d[cur ^ 1][in].push(t, d[cur][in].dp[k]); 105 tp(t, j - 1, 1), tp(t, j, 2); 106 if(i + 1 <= n && j + 1 <= m) { 107 if (jud(i - 1, j, in) && jud(i, j - 1, in) && jud(i, j, 1 ^ in)) 108 d[cur ^ 1][in].push(t, d[cur][in].dp[k] + 1); 109 } 110 } 111 } 112 } 113 114 int main() { 115 int T; 116 scanf("%d", &T); 117 int cas = 0; 118 while (T-- > 0) { 119 scanf("%d%d", &n, &m); 120 memset(a, 0, sizeof a); 121 for (int i = 1; i <= n; ++i) { 122 scanf("%s", a[i] + 1); 123 } 124 ++n, ++m; 125 ex = 0, ey = 0; 126 for(int i = 1; i <= n; ++i) a[i][m] = '.'; 127 for(int j = 1; j <= m; ++j) a[n][j] = '.'; 128 for (int i = 1; i <= n; ++i) 129 for (int j = 1; j <= m; ++j) if (a[i][j] == 'o') 130 ex = i, ey = j; 131 132 int cur = 0; 133 d[0][0].init(); 134 d[0][1].init(); 135 d[0][0].push(0, 0); 136 ans = (int)1e9; 137 for (int i = 1; i <= n; ++i) { 138 for (int j = 1; j <= m; ++j) { 139 d[cur ^ 1][0].init(); 140 d[cur ^ 1][1].init(); 141 blank(i, j, cur, 0); 142 blank(i, j, cur, 1); 143 cur ^= 1; 144 } 145 for (int j = 0; j < d[cur][0].cnt; ++j) 146 d[cur][0].st[j] <<= 2; 147 for (int j = 0; j < d[cur][1].cnt; ++j) 148 d[cur][1].st[j] <<= 2; 149 } 150 printf("Case #%d: ", ++cas); 151 if (ans == (int)1e9) puts("-1"); 152 else printf("%d\n", ans); 153 } 154 return 0; 155 }