【插头DP】HDU 1693 Eat the Trees
通道:http://acm.hdu.edu.cn/showproblem.php?pid=1693
题意:多回路路径方案数,无障碍。
代码:
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 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 void blank(int i, int j, int cur) { 62 for(int k = 0; k < d[cur].cnt; ++k) { 63 long long t = d[cur].st[k]; 64 int l = find_pos(t, j - 1), r = find_pos(t, j); 65 if(l && r) { 66 if(l == 1 && r == 1) { 67 int tpos = find_r(t, j); 68 tp(t, j - 1, 0); tp(t, j, 0); tp(t, tpos, 1); 69 d[cur ^ 1].push(t, d[cur].dp[k]); 70 } else if(l == 2 && r == 1) { 71 tp(t, j - 1, 0); tp(t, j, 0); 72 d[cur ^ 1].push(t, d[cur].dp[k]); 73 } else if(l == 2 && r == 2) { 74 int tpos = find_l(t, j - 1); 75 tp(t, j - 1, 0); tp(t, j, 0); tp(t, tpos, 2); 76 d[cur ^ 1].push(t, d[cur].dp[k]); 77 } else { // 最后一个非障碍格子 78 tp(t, j - 1, 0); tp(t, j, 0); 79 d[cur ^ 1].push(t, d[cur].dp[k]); 80 } 81 } else if(l) { 82 if(i < n) { 83 d[cur ^ 1].push(t, d[cur].dp[k]); 84 } 85 if(j < m) { 86 tp(t, j - 1, 0); tp(t, j, l); 87 d[cur ^ 1].push(t, d[cur].dp[k]); 88 } 89 } else if(r) { 90 if(j < m) { 91 d[cur ^ 1].push(t, d[cur].dp[k]); 92 } 93 if(i < n) { 94 tp(t, j - 1, r); tp(t, j, 0); 95 d[cur ^ 1].push(t, d[cur].dp[k]); 96 } 97 } else { // 新建 98 if(i < n && j < m) { 99 tp(t, j - 1, 1); tp(t, j, 2); 100 d[cur ^ 1].push(t, d[cur].dp[k]); 101 } 102 } 103 } 104 } 105 106 void block(int i, int j, int cur) { 107 for (int k = 0; k < d[cur].cnt; ++k) { 108 long long t = d[cur].st[k]; 109 int l = find_pos(t, j - 1), r = find_pos(t, j); 110 if (!l && !r) d[cur ^ 1].push(t, d[cur].dp[k]); 111 } 112 } 113 114 char str[17]; 115 int a[MAX_N][MAX_M]; 116 117 int main() { 118 int T; 119 scanf("%d", &T); 120 int cas = 0; 121 while (T-- > 0) { 122 scanf("%d%d", &n, &m); 123 memset(a, 0, sizeof a); 124 for (int i = 1; i <= n; ++i) { 125 for (int j = 1; j <= m; ++j) { 126 scanf("%d", &a[i][j]); 127 } 128 } 129 long long ans = 0; 130 int cur = 0; 131 d[cur].init(); 132 d[cur].push(0, 1); 133 for (int i = 1; i <= n; ++i) { 134 for (int j = 1; j <= m; ++j) { 135 d[cur ^ 1].init(); 136 if (a[i][j]) blank(i, j, cur); 137 else block(i, j, cur); 138 cur ^= 1; 139 } 140 for (int j = 0; j < d[cur].cnt; ++j) 141 d[cur].st[j] <<= 2; 142 } 143 for (int i = 0; i < d[cur].cnt; ++i) if(d[cur].st[i] == 0) 144 ans += d[cur].dp[i]; 145 printf("Case %d: There are %I64d ways to eat the trees.\n", ++cas, ans); 146 } 147 return 0; 148 }