这题可以说是正式的插头dp,需要对插头标号,虽然研读了hh的模板和论文,但写起来还是花了很多时间,主要是细节方面的东西,比如第一列和最后一列需要特殊讨论,还有最后一个合法格子也需要特殊讨论
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <utility> #include <ctime> using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::istringstream; using std::make_pair; using std::getline; using std::greater; using std::endl; using std::multimap; using std::deque; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PAIR; typedef multimap<int, int> MMAP; const int MAXN(1000010); const int MAXM(10010); const int MAXE(10010); const int HSIZE(13131); const int SIGMA_SIZE(26); const int MAXH(19); const int INFI(2000000000); const int MOD(100000000); const ULL BASE(31); const LL LIM(10000000); const int INV(-10000); struct HASH_MAP { int first[HSIZE], next[MAXN]; LL state[MAXN]; LL value[MAXN]; int size; void init() { memset(first, -1, sizeof(first)); size = 0; } void insert(LL ts, LL tv) { int h = ts%HSIZE; for(int i = first[h]; ~i; i = next[i]) if(state[i] == ts) { value[i] += tv; return; } state[size] = ts; value[size] = tv; next[size] = first[h]; first[h] = size++; } }hm[2]; HASH_MAP *cur, *last; char mp[15][15]; int code[13]; int Num[13]; inline void decode(int m, LL ts) { for(int i = 0; i <= m; ++i) { code[i] = ts&7; ts >>= 3; } } inline LL encode(int m) { LL ret = 0; int cnt = 0; memset(Num, -1, sizeof(Num)); for(int i = m; i >= 0; --i) if(code[i] == 0) ret <<= 3; else { if(Num[code[i]] < 0) Num[code[i]] = ++cnt; ret = (ret << 3)|Num[code[i]]; } return ret; } int li, lj; inline bool lastgrid(int i, int j){ return i == li && j == lj;} void updata(int i, int j, int m, LL tv) { int up = (i == 0)? 0: code[j+1]; int left = (j == 0)? 0: code[j]; if(mp[i][j] == '*') { if(up == 0 && left == 0) { code[j] = code[j+1] = 0; cur->insert(encode(m), tv); } return; } if(up == 0 && left == 0) { if(j == m-1) //最后一列不允许有右插头 return; code[j] = code[j+1] = 7; } else if(up == 0 || left == 0) { code[j] = up+left; code[j+1] = 0; cur->insert(encode(m), tv); if(j == m-1) //最后一列不允许有右插头 return; code[j] = 0; code[j+1] = up+left; cur->insert(encode(m), tv); return; } else if(up != left) { if(lastgrid(i, j)) return; for(int i = 0; i <= m; ++i) if(code[i] == up) code[i] = left; code[j] = code[j+1] = 0; } else if(lastgrid(i, j)) //只有最后一个格子允许连接成一条回路 code[j] = code[j+1] = 0; else return; cur->insert(encode(m), tv); } void solve(int n, int m) { cur = hm; last = hm+1; last->init(); last->insert(0, 1); for(int i = 0; i < n; ++i) for(int j = 0; j < m; ++j) { cur->init(); int sz = last->size; for(int k = 0; k < sz; ++k) { decode(m, last->state[k]); if(j == 0) for(int k2 = m; k2 >= 1; --k2) //另起一行时需要把编码整体右移 code[k2] = code[k2-1]; updata(i, j, m, last->value[k]); } if(lastgrid(i, j)) { LL ans = 0; for(int i = 0; i < cur->size; ++i) if(cur->state[i] == 0) { ans = cur->value[i]; break; } printf("%I64d\n", ans); return; } swap(cur, last); } } int main() { int n, m; while(~scanf("%d%d", &n, &m)) { for(int i = 0; i < n; ++i) scanf("%s", mp[i]); li = lj = -1; for(int i = n-1; i >= 0; --i) { for(int j = m-1; j >= 0; --j) if(mp[i][j] == '.') { li = i; lj = j; break; } if(~li) break; } if(li == -1) printf("0\n"); else solve(n, m); } return 0; }
括号表示法(对于回路问题效率要比最小表示法高)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <utility> #include <ctime> using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::istringstream; using std::make_pair; using std::getline; using std::greater; using std::endl; using std::multimap; using std::deque; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PAIR; typedef multimap<int, int> MMAP; const int MAXN(20010); const int MAXM(5010); const int MAXE(10010); const int HSIZE(13131); const int SIGMA_SIZE(26); const int MAXH(19); const int INFI((INT_MAX-1) >> 1); const int MOD(123456791); const ULL BASE(31); const LL LIM(10000000); const int INV(-10000); int N, M; char mp[15][15]; struct HASH_MAP { int first[HSIZE]; int next[MAXN], state[MAXN]; LL value[MAXN]; int size; void init() { memset(first, -1, sizeof(first)); size = 0; } void insert(int ts, LL tv) { int h = ts%HSIZE; for(int i = first[h]; ~i; i = next[i]) if(state[i] == ts) { value[i] += tv; return; } value[size] = tv; state[size] = ts; next[size] = first[h]; first[h] = size++; } } hm[2]; HASH_MAP *cur, *last; int acc[4] = {0, -1, 1, 0}; //无插头,左括号,右括号 inline int getB(int ts, int i){ return (ts >> (i << 1))&3;} //获得指定位 inline int getLB(int ts, int i) //通过右括号找到左括号 { int ret = i, cnt = 1; while(cnt) { --ret; cnt += acc[getB(ts, ret)]; } return ret; } inline int getRB(int ts, int i) //通过左括号找到右括号 { int ret = i, cnt = -1; while(cnt) { ++ret; cnt += acc[getB(ts, ret)]; } return ret; } inline void setB(int &ts, int i, int tv){ts = (ts&~(3 << (i << 1)))|(tv << (i << 1));} //设置指定位 int lx, ly; inline bool lastgrid(int x, int y){return x == lx && y == ly;} void updata(int x, int y, int ts, LL tv) { int left = (y == 0)? 0: getB(ts, y); int up = (x == 0)? 0: getB(ts, y+1); int tts; if(mp[x][y] == '*') { if(left == 0 && up == 0) { tts = ts; setB(tts, y, 0); setB(tts, y+1, 0); cur->insert(tts, tv); } return; } if(left == 0 && up == 0) { if(x == N-1 || y == M-1) return; tts = ts; setB(tts, y, 1); setB(tts, y+1, 2); cur->insert(tts, tv); } else if(left == 0 || up == 0) { if(x < N-1) { tts = ts; setB(tts, y, up+left); setB(tts, y+1, 0); cur->insert(tts, tv); } if(y < M-1) { tts = ts; setB(tts, y, 0); setB(tts, y+1, up+left); cur->insert(tts, tv); } } else { tts = ts; setB(tts, y, 0); setB(tts, y+1, 0); if(left == 1 && up == 1) { setB(tts, getRB(ts, y+1), 1); cur->insert(tts, tv); } else if(left == 1 && up == 2) { if(!lastgrid(x, y)) return; cur->insert(tts, tv); } else if(left == 2 && up == 1) { cur->insert(tts, tv); } else if(left == 2 && up == 2) { setB(tts, getLB(ts, y), 2); cur->insert(tts, tv); } } } void solve() { cur = hm; last = hm+1; last->init(); last->insert(0, 1); for(int i = 0; i < N; ++i) { int sz = last->size; for(int k = 0; k < sz; ++k) last->state[k] <<= 2; for(int j = 0; j < M; ++j) { cur->init(); sz = last->size; for(int k = 0; k < sz; ++k) updata(i, j, last->state[k], last->value[k]); swap(cur, last); } } LL ans = 0; for(int i = 0; i < last->size; ++i) if(last->state[i] == 0) { ans = last->value[i]; break; } printf("%I64d\n", ans); } int main() { while(~scanf("%d%d", &N, &M)) { for(int i = 0; i < N; ++i) scanf("%s", mp[i]); lx = -1; ly = -1; for(int i = N-1; i >= 0 && lx == -1; --i) for(int j = M-1; j >= 0; --j) if(mp[i][j] == '.') { lx = i; ly = j; break; } solve(); } return 0; }