BZOJ1814 Ural 1519 Formula 1
插头dp的练手题么。虽然之前还没写过哈密顿回路的题。
学习了一下广义括号法。发现状态数比之前记连通性的方法要少。仔细想想发现,两个连通的插头的顺序有关。不能存在1212这种东西。所以连通性的方法记了很多废状态。那把连通性方法改进一下会不会变得更快呢?可以研究一下。我觉得应该是等效了吧。
今天的debug时间明显缩短了。虽然还是debug了老半天。然后怎么代码还是那么长。想起我每次都觉得把东西挤到一起看起来很不雅观,于是去写一堆找转移的函数。晕。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long dint; #ifdef WIN32 #define lld "%I64d" #else #define lld "%lld" #endif #define _l (long long int) const int maxn = 15; const int maxst = 50009; #define mbit(_x_,_y_) ((_x_)<<((_y_)<<1)) #define gbit(_x_,_y_) (((_x_)>>((_y_)<<1))&3) #define cbit(_x_,_y_) ((_x_)&(~(3<<((_y_)<<1)))) int n, m, tots, slst[maxst]; bool mp[maxn][maxn]; dint f[2][maxst]; void dfsState(int l, int c, int z) { if (l == m + 1) { if (!c) slst[tots ++] = z; } else { dfsState(l + 1, c, z); dfsState(l + 1, c + 1, z | mbit(1, l)); if (c) dfsState(l + 1, c - 1, z | mbit(2, l)); } } void preState() { tots = 0; dfsState(0, 0, 0); sort(slst, slst + tots); } inline int fState(int s) { register int ret(lower_bound(slst, slst + tots, s) - slst); if (slst[ret] != s) puts("naive"); return ret; } #define inc(_a_,_b_) (_a_+=_b_) inline int brv(int x) { if (!x) return 0; else return (x == 1) ? 1 : -1; } bool isEnd(int s, int y) { for (int i = 0; i < y; ++ i) if (gbit(s, i)) return 0; for (int i = y + 2; i <= m; ++ i) if (gbit(s, i)) return 0; return 1; } inline int mergePlug(int s, int y) { int p, c; if (gbit(s, y) != gbit(s, y + 1)) { s = cbit(s, y); s = cbit(s, y + 1); return fState(s); } else if (gbit(s, y) == 1) { for (c = 1, p = y + 1; c; ++ p, c += brv(gbit(s, p))); s = cbit(s, y); s = cbit(s, y + 1); s = cbit(s, p); return fState(s | mbit(1, p)); } else { for (c = -1, p = y; c; -- p, c += brv(gbit(s, p))); s = cbit(s, y); s = cbit(s, y + 1); s = cbit(s, p); return fState(s | mbit(2, p)); } } inline int extPlugRight(int s, int y) { s |= mbit(gbit(s, y), y + 1); s = cbit(s, y); return fState(s); } inline int extPlugDown(int s, int y) { s |= mbit(gbit(s, y + 1), y); s = cbit(s, y + 1); return fState(s); } inline int forkPlug(int s, int y) { s |= mbit(1, y); s |= mbit(2, y + 1); return fState(s); } inline int nextRow(int s) { int r(0); for (int i = 0; i < m; ++ i) r |= mbit(gbit(s, i), i + 1); return fState(r); } dint dp() { int cur(0), prv(1); dint ans; memset(f, 0, sizeof(f)); f[cur][0] = 1; for (int x = 0; x < n; ++ x) { for (int y = 0; y < m; ++ y) { if (mp[x][y]) ans = 0; swap(cur, prv); memset(f[cur], 0, sizeof(f[cur])); for (int i = 0; i < tots; ++ i) if (f[prv][i]) { int s(slst[i]);; if (mp[x][y]) { if (gbit(s, y) && gbit(s, y + 1)) { if (gbit(s, y) == 1 && gbit(s, y + 1) == 2) { if (isEnd(s, y)) inc(ans, f[prv][i]); } else inc(f[cur][mergePlug(s, y)], f[prv][i]); } else if (gbit(s, y)) { inc(f[cur][i], f[prv][i]); inc(f[cur][extPlugRight(s, y)], f[prv][i]); } else if (gbit(s, y + 1)) { inc(f[cur][i], f[prv][i]); inc(f[cur][extPlugDown(s, y)], f[prv][i]); } else inc(f[cur][forkPlug(s, y)], f[prv][i]); } else { if (!gbit(s, y) && !gbit(s, y + 1)) inc(f[cur][i], f[prv][i]); } } } swap(cur, prv); memset(f[cur], 0, sizeof(f[cur])); for (int i = 0; i < tots; ++ i) if (f[prv][i] && !gbit(slst[i], m)) inc(f[cur][nextRow(slst[i])], f[prv][i]); } return ans; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif scanf("%d%d", &n, &m); for (int i = 0; i < n; ++ i) { char g[maxn]; scanf("%s", g); for (int j = 0; j < m; ++ j) mp[i][j] = (g[j] == '.'); } preState(); printf(lld "\n", dp()); }