从上题的多环到这题的单环要考虑的东东多了, 插头也成了两种, 因此用到了三进制(即括号表示法中的'#','(',')'), 直接用三进制, 大量的除法和取余运算常数可能会大, 从而超时, 因此应该用4进制位运算会更好一些, 然后再存储状态方案数时再转三进制进行hash, 当然hash的方法还可以是别的复杂度不高的函数.
/******************************************************** ** Author : Huikang Yih ** Email : [email protected] ** Date : 2014-11-29 16:37 ** For : Ural 1519. Formula 1 *********************************************************/ #include <vector> #include <map> #include <set> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <iostream> #include <cstdio> #include <cmath> #include <cstdlib> #include <ctime> #include <string> #include <cstring> using namespace std; typedef double DB; typedef unsigned int UI; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PII; typedef map<int, int> MPII; typedef vector<int> VI; typedef vector<bool> VB; typedef vector<char> VC; typedef vector<double> VD; typedef vector<string> VS; typedef vector<VI> VVI; typedef vector<PII> VPII; template <class T> inline bool checkMin(T& a, T b) { if (b < a) { a = b; return true; } return false; } template <class T> inline bool checkMax(T& a, T b) { if (b > a) { a = b; return true; } return false; } const int N = 15; const int M = 2000005; /*****************************************************************************************************/ struct mStack { int top, arr[M]; inline void clear() { top = 0; } inline void push(int x) { arr[top ++] = x; } inline int pop() { return arr[-- top]; } inline bool empty() { return !top; } inline int size() { return top; } }; // 自定义栈 /*****************************************************************************************************/ int n, m, nn, mm, g[N][N]; int pre, now; mStack stk[2]; int visCount, vis[M]; // 访问标记 LL sum[2][M]; inline int mHash(int s) { // '四进制' 转 '三进制' int ret = 0; for (int i = 0, x = 1; i < m; i++, x *= 3) { ret += (s & 3) * x; s >>= 2; } return ret; } void update(int s, LL data) { // 更新函数 int x = mHash(s); if (vis[x] != visCount) { sum[now][x] = data; vis[x] = visCount; stk[now].push(s); } else sum[now][x] += data; } inline LL solve() { visCount = 0; memset(vis, -1, sizeof(vis)); stk[pre = 1].clear(); stk[now = 0].clear(); // 初始化 update(0, 1); // 初始边界量 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { pre ^= 1, now ^= 1; visCount ++; // 滚动数组及栈(或队列) if (stk[pre].empty()) return 0LL; // 无解, 提前退出 while (!stk[pre].empty()) { int s = stk[pre].pop(); long long data = sum[pre][mHash(s)]; if (j == 1) { if (s & (1 << (m << 1))) continue; s <<= 2; } // 首列 int left = s >> ((j - 1) << 1) & 3; int up = s >> (j << 1) & 3; int s0 = s ^ (left << ((j - 1) << 1)) ^ (up << (j << 1)); // 特征插头值 if (!g[i][j]) { if (!left && !up) update(s0, data); continue; } // 障碍格子 if (!left && !up) { if (g[i][j + 1] && g[i + 1][j]) update(s0 | (9 << ((j - 1) << 1)), data); continue; } // 新生插头 if ((!left) ^ (!up)) { if (g[i + 1][j]) update(s0 | ((left | up) << ((j - 1) << 1)), data); if (g[i][j + 1]) update(s0 | ((left | up) << (j << 1)), data); continue; } // 维持插头原态 if (left == 1 && up == 2) { if (i == nn && j == mm) update(s0, data); continue; } // 并列12插头 if (left == 2 && up == 1) { update(s0, data); continue; } // 并列21插头 if (left == 1 && up == 1) { int cnt = 1, idx = j; while (cnt > 0) { idx ++; int w = s >> ((idx) << 1) & 3; if (w == 1) cnt ++; if (w == 2) cnt --; } update(s0 ^ (3 << (idx << 1)), data); continue; } // 并列11插头 if (left == 2 && up == 2) { int cnt = 1, idx = j - 1; while (cnt > 0) { idx --; int w = s >> (idx << 1) & 3; if (w == 1) cnt --; if (w == 2) cnt ++; } update(s0 ^ (3 << (idx << 1)), data); continue; } // 并列22插头 cout << "error happens." << endl; // 如果执行了此语句, 则说明四进制编码有错 } if (i == nn && j == mm) return sum[now][0]; // 最后一个非障碍格子 } } return -1; // 出错, nn, mm不对返回-1 } int main() { scanf("%d%d", &n, &m); memset(g, 0, sizeof(g)); int xxx = 0; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { char x = getchar(); while (x != '.' && x != '*') x = getchar(); if (x == '.') { g[i][j] = true; nn = i; mm = j; xxx ++; } } } if (xxx & 1) printf("0\n"); else printf("%I64d\n", solve()); return 0; }