这是一道经典的插头DP单回路模板题。
用最小表示法来记录连通性,由于二进制的速度,考虑使用8进制。
1、当同时存在左、上插头的时候,需要判断两插头所在连通块是否相同,若相同,只能在最后一个非障碍点相连;若不相同,则把这两个连通块连起来。
2、如果只存在左或上插头的时候,则要延续连通块。
3、若都不存在左和上插头的时候,就要新建一个连通块。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <string> 5 #include <algorithm> 6 7 using namespace std; 8 9 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i) 10 #define DWN(i, a, b) for (int i = (a), i##_end_ = (b); i >= i##_end_; --i) 11 #define mset(a, b) memset(a, b, sizeof(a)) 12 typedef long long LL; 13 const int MAXD = 15, HASH = 30007, STATE = 100010; 14 int n, m, maze[MAXD][MAXD], code[MAXD], ch[MAXD], end_x, end_y; 15 char str[MAXD]; 16 struct HASHMAP 17 { 18 int head[HASH], nxt[STATE], siz; LL f[STATE], state[STATE]; 19 void clear() { siz = 0, mset(head, -1); } 20 void push(LL x, LL add) 21 { 22 int pos = x%HASH, i = head[pos]; 23 for (; i != -1; i = nxt[i]) 24 if (state[i] == x) { f[i] += add; return ; } 25 state[siz] = x, f[siz] = add; 26 nxt[siz] = head[pos], head[pos] = siz++; 27 } 28 }hm[2]; 29 30 void in() 31 { 32 scanf("%d %d", &n, &m), mset(maze, 0), end_x = end_y = -1; 33 REP(i, 1, n) 34 { 35 scanf("%s", str+1); 36 REP(j, 1, m) 37 if (str[j] == '.') 38 maze[i][j] = 1, end_x = i, end_y = j; 39 } 40 } 41 42 void decode(LL x) 43 { 44 REP(i, 0, m) code[i] = x&7, x >>= 3; 45 } 46 47 LL encode() 48 { 49 LL ret = 0; int cnt = 0; 50 mset(ch, -1), ch[0] = 0; 51 DWN(i, m, 0) 52 { 53 if (ch[code[i]] == -1) ch[code[i]] = ++cnt; 54 ret <<= 3, ret |= ch[code[i]]; 55 } 56 return ret; 57 } 58 59 void shift(int j) 60 { 61 if (j != m) return ; 62 DWN(i, m, 1) code[i] = code[i-1]; 63 code[0] = 0; 64 } 65 66 void dp_blank(int i, int j, int cur) 67 { 68 REP(k, 0, hm[cur].siz-1) 69 { 70 decode(hm[cur].state[k]); 71 int lef = code[j-1], up = code[j]; 72 if (lef && up) 73 { 74 if (lef == up && !(i == end_x && j == end_y)) continue ; 75 REP(t, 0, m) 76 if (code[t] == up) code[t] = lef; 77 code[j-1] = code[j] = 0, shift(j); 78 hm[cur^1].push(encode(), hm[cur].f[k]); 79 } 80 else 81 if (lef || up) 82 { 83 int t = lef ? lef : up; 84 if (maze[i][j+1]) 85 { 86 code[j-1] = 0, code[j] = t; 87 hm[cur^1].push(encode(), hm[cur].f[k]); 88 } 89 if (maze[i+1][j]) 90 { 91 code[j-1] = t, code[j] = 0, shift(j); 92 hm[cur^1].push(encode(), hm[cur].f[k]); 93 } 94 } 95 else 96 if (maze[i][j+1] && maze[i+1][j]) 97 { 98 code[j-1] = code[j] = 13, shift(j); 99 hm[cur^1].push(encode(), hm[cur].f[k]); 100 } 101 } 102 } 103 104 void dp_block(int i, int j, int cur) 105 { 106 REP(k, 0, hm[cur].siz-1) 107 { 108 decode(hm[cur].state[k]), shift(j); 109 hm[cur^1].push(encode(), hm[cur].f[k]); 110 } 111 } 112 113 void work() 114 { 115 int cur = 0; LL ans = 0; 116 hm[0].clear(), hm[1].clear(), hm[cur].push(0, 1); 117 REP(i, 1, n) 118 REP(j, 1, m) 119 { 120 if (maze[i][j]) dp_blank(i, j, cur); 121 else dp_block(i, j, cur); 122 hm[cur].clear(), cur ^= 1; 123 } 124 REP(i, 0, hm[cur].siz-1) ans += hm[cur].f[i]; 125 printf("%I64d ", ans); 126 } 127 128 int main() 129 { 130 in(); 131 work(); 132 return 0; 133 }