【插头DP】 FZU 1977 Pandora adventure
通道:http://acm.fzu.edu.cn/problem.php?pid=1977
题意:单回路,有障碍点,必走点和非必走点。
思路:由于有格子可以不经过,那么就导致最后一个格子无法确定,我们找到输入中最后一个无障碍的格子,那么计算的时候,以后的格子作为最后一个即可。
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 = 100007; 11 12 struct node { 13 int head[HASH], nxt[MAX_S]; 14 long long dp[MAX_S], st[MAX_S]; 15 int cnt; 16 void init() { 17 memset(head, -1, sizeof head); 18 cnt = 0; 19 } 20 void push(long long s, long long v) { 21 int now = s % HASH; 22 for(int i = head[now]; ~i; i = nxt[i]) if(st[i] == s) { 23 dp[i] += v; 24 return ; 25 } 26 st[cnt] = s; dp[cnt] = v; 27 nxt[cnt] = head[now]; 28 head[now] = cnt++; 29 } 30 }d[2]; 31 32 int n, m; 33 34 int find_pos(long long s, int p) { 35 return (s >> (p << 1)) & 3; 36 } 37 38 void tp(long long &s, int p, long long v) { 39 s &= (~(3ll << (p << 1))); 40 s |= (v << (p << 1)); 41 } 42 43 int find_r(long long s, int p) { 44 int cnt = 0; 45 for(int i = p; i <= m; ++i) { 46 if(find_pos(s, i) == 1) ++cnt; 47 else if(find_pos(s, i) == 2) --cnt; 48 if(!cnt) return i; 49 } 50 } 51 52 int find_l(long long s, int p) { 53 int cnt = 0; 54 for(int i = p; i >= 0; --i) { 55 if(find_pos(s, i) == 2) ++cnt; 56 else if(find_pos(s, i) == 1) --cnt; 57 if(!cnt) return i; 58 } 59 } 60 61 long long ans1; 62 int ex, ey; 63 int a[MAX_N][MAX_M]; 64 65 void blank(int i, int j, int cur) { 66 for(int k = 0; k < d[cur].cnt; ++k) { 67 long long t = d[cur].st[k]; 68 int l = find_pos(t, j - 1), r = find_pos(t, j); 69 if(l && r) { 70 if(l == 1 && r == 1) { 71 int tpos = find_r(t, j); 72 tp(t, j - 1, 0); tp(t, j, 0); tp(t, tpos, 1); 73 d[cur ^ 1].push(t, d[cur].dp[k]); 74 } else if(l == 2 && r == 1) { 75 tp(t, j - 1, 0); tp(t, j, 0); 76 d[cur ^ 1].push(t, d[cur].dp[k]); 77 } else if(l == 2 && r == 2) { 78 int tpos = find_l(t, j - 1); 79 tp(t, j - 1, 0); tp(t, j, 0); tp(t, tpos, 2); 80 d[cur ^ 1].push(t, d[cur].dp[k]); 81 } else { // 最后一个非障碍格子 82 tp(t, j - 1, 0); tp(t, j, 0); 83 if (!t) { 84 if (i > ex || i == ex && j >= ey) 85 ans1 += d[cur].dp[k]; 86 } 87 } 88 } else if(l) { 89 if(i < n) { 90 d[cur ^ 1].push(t, d[cur].dp[k]); 91 } 92 if(j < m) { 93 tp(t, j - 1, 0); tp(t, j, l); 94 d[cur ^ 1].push(t, d[cur].dp[k]); 95 } 96 } else if(r) { 97 if(j < m) { 98 d[cur ^ 1].push(t, d[cur].dp[k]); 99 } 100 if(i < n) { 101 tp(t, j - 1, r); tp(t, j, 0); 102 d[cur ^ 1].push(t, d[cur].dp[k]); 103 } 104 } else { // 新建 105 if (a[i][j] == 1) d[cur ^ 1].push(t, d[cur].dp[k]); 106 if(i < n && j < m) { 107 tp(t, j - 1, 1); tp(t, j, 2); 108 d[cur ^ 1].push(t, d[cur].dp[k]); 109 } 110 } 111 } 112 } 113 114 void block(int i, int j, int cur) { 115 for (int k = 0; k < d[cur].cnt; ++k) { 116 long long t = d[cur].st[k]; 117 int l = find_pos(t, j - 1), r = find_pos(t, j); 118 if (!l && !r) d[cur ^ 1].push(t, d[cur].dp[k]); 119 } 120 } 121 122 char str[20]; 123 124 int main() { 125 int T; 126 int cas = 0; 127 scanf("%d", &T); 128 while (T-- > 0) { 129 memset(a, 0, sizeof a); 130 scanf("%d%d", &n, &m); 131 for (int i = 1; i <= n; ++i) { 132 scanf("%s", str + 1); 133 for (int j = 1; j <= m; ++j) { 134 if (str[j] == '*') a[i][j] = 1; 135 else if (str[j] == 'O') a[i][j] = 2, ex = i, ey = j; 136 } 137 } 138 int cur = 0; 139 d[cur].init(); 140 d[cur].push(0, 1); 141 ans1 = 0; 142 for (int i = 1; i <= n; ++i) { 143 for (int j = 1; j <= m; ++j) { 144 d[cur ^ 1].init(); 145 if (a[i][j]) blank(i, j, cur); 146 else block(i, j, cur); 147 cur ^= 1; 148 } 149 for (int j = 0; j < d[cur].cnt; ++j) 150 d[cur].st[j] <<= 2; 151 } 152 printf("Case %d: %I64d\n", ++cas, ans1); 153 } 154 return 0; 155 } 156 157 /* 158 159 4 160 2 2 161 OO 162 OX 163 2 2 164 OO 165 O* 166 3 3 167 OOO 168 OO* 169 OOO 170 4 4 171 ***O 172 XO** 173 **O* 174 XX** 175 176 */
TAG:对于状态的计算,还是直接在L=1,R=2时计算吧,就不要往后面再转移了。