极其仰慕 邝斌 巨巨!!!!!! Orz
http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710343.html
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=23691#overview
最简单的,表示一下就行了。。
注意转移。
第一次照木板敲,以后就学会了把。。。
const int N = 20; int n , m; int code[N] , a[N][N]; const int HashSize = 1e4 + 9; const int StateSize = 1e6 + 9; struct HashMap{ int head[HashSize] , next[StateSize] , state[StateSize] , size; LL f[StateSize]; void init(){ size = 0; FLC(head , -1); } void push(int st , LL inc){ int h = st % HashSize; for (int i = head[h] ; ~i ; i = next[i]) if (st == state[i]){ f[i] += inc; return; } f[size] = inc; state[size] = st; next[size] = head[h]; head[h] = size++; } }H[2]; int encode(int * code , int m){ int st = 0; for (int i = 0 ; i <= m ; ++i) st = st << 1 | code[i]; return st; } void decode(int * code , int m , int st){ for (int i = m ; i >= 0 ; --i){ code[i] = st & 1; st >>= 1; } } void shift(int *code , int m){ // Another Line for (int i = m ; i > 0 ; --i) code[i] = code[i - 1]; code[0] = 0; } void dpblank(int x , int y , int cur){ int left , up; for (int i = 0 ; i < H[cur].size ; ++i){ decode(code , m , H[cur].state[i]); left = code[y - 1]; up = code[y]; if (left && up){ // 11 -> 00 code[y - 1] = code[y] = 0; if (y == m) shift(code , m); H[cur ^ 1].push( encode(code , m) , H[cur].f[i] ); } else if (left || up){ // 10 | 01 if (a[x][y + 1]){ // Go right code[y - 1] = 0; code[y] = 1; if (y == m) shift(code , m); H[cur ^ 1].push(encode(code , m) , H[cur].f[i]); } if (a[x + 1][y]){ // Go down code[y - 1] = 1; code[y] = 0; if (y == m) shift(code , m); H[cur ^ 1].push(encode(code , m) , H[cur].f[i]); } } else{ // 00 if (a[x][y + 1] && a[x + 1][y]){ // down to right code[y] = code[y - 1] = 1; H[cur ^ 1].push(encode(code , m) , H[cur].f[i]); } } } } void dpblock(int x , int y , int cur){ for (int i = 0 ; i < H[cur].size ; ++i){ decode(code , m , H[cur].state[i]); code[y - 1] = code[y] = 0; if (y == m) shift(code , m); H[cur ^ 1].push(encode(code , m) , H[cur].f[i]); } } int Case; void solve(){ scanf("%d%d" , &n , &m); for (int i = 1 ; i <= n ; ++i) for (int j = 1 ; j <= m ; ++j) scanf("%d" , &a[i][j]); for (int i = 1 ; i <= n ; ++i) a[i][0] = a[i][m + 1] = 0; for (int i = 1 ; i <= m ; ++i) a[0][i] = a[n + 1][i] = 0; LL ans = 0; int cur = 0; H[cur].init(); H[cur].push(0 , 1); for (int i = 1 ; i <= n ; ++i) for (int j = 1 ; j <= m ; ++j){ H[cur ^ 1].init(); if (a[i][j]) dpblank(i , j , cur); else dpblock(i , j , cur); cur ^= 1; } for (int i = 0 ; i < H[cur].size ; i++) ans += H[cur].f[i]; printf("Case %d: There are %I64d ways to eat the trees.\n",++Case , ans); } int main(){ int _;Case = 0; cin >> _; while(_--) solve(); }
三进制 -> 四进制的括号表示
括号表示还是相当快的!
http://blog.sina.com.cn/s/blog_51cea4040100gmky.html
这个blog 写的很清楚 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑
struct Hashmap{ const static int HASHSIZE = 1e5 + 7; const static int STATUSSIZE = 1e5 + 9; int head[HASHSIZE]; struct hash_item{ int key; LL val; int next; }item[STATUSSIZE + 1]; int L; int getHash(int x){ return x % HASHSIZE; } void init(){ memset(head , -1 , sizeof(head)); L = 0; } void clear(){ for (int i = 0; i < L ; ++i) head[getHash(item[i].key)] = -1; L = 0; } int contains(int x){ for (int i = head[getHash(x)]; i != -1 ; i = item[i].next) if (item[i].key == x) return i; return -1; } void insert(int x){ int tmp = getHash(x); item[L].key = x; item[L].val = 0; item[L].next = head[tmp]; head[tmp] = L++; } LL& operator[] (int x){ int tmp = contains(x); if (tmp == -1){ insert(x); return item[L - 1].val; } else return item[tmp].val; } }hm[2]; const int N = 15; int n , m; int code[N] , a[N][N]; int ex , ey; char str[N]; void shift(int &code){ code <<= 2; int mm = (m + 1) << 1; code &= ((1 << mm) - 1); } int getplug(int cur , int y){ cur >>= 2 * y; int ret = cur & 1; cur >>= 1; ret |= (cur & 1) << 1; return ret; } void setplug(int &cur , int y , int key){ if ( ((cur >> (y << 1)) & 1) ^ (key & 1) ) cur ^= 1 << (y << 1); if ( ((cur >> (y << 1 | 1)) & 1) ^ ((key >> 1) & 1) ) cur ^= 1 << (y << 1 | 1); } void dpblank(int x , int y , int cur){ int left , up; int aft; for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){ aft = hm[cur].item[i].key; left = getplug(hm[cur].item[i].key , y - 1); up = getplug(hm[cur].item[i].key , y); if (left == 0 && up == 0){ //无插头,新建联通分量 if (a[x + 1][y] && a[x][y + 1]){ setplug(aft , y - 1 , 1); setplug(aft , y , 2); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } } else if (left && up){ // 有两个插头 ! 要删掉上插头和左插头啊 if (left == 1 && up == 1){ // (( 找到下一个对应的 ) 改成 ( int top = 0; for (int j = y ; j <= m ; ++j){ int plug = getplug(hm[cur].item[i].key , j); if (plug == 1) ++top; if (plug == 2) --top; if (top == 0){ setplug(aft , j , 1); break; } } setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } else if (left == 2 && up == 2){ // )) 找到上一个对应的 ( 变成 ) int top = 0; for (int j = y - 1 ; j >= 0 ; --j){ int plug = getplug(hm[cur].item[i].key , j); if (plug == 2) ++top; if (plug == 1) --top; if (top == 0){ setplug(aft , j , 2); break; } } setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } else if (left == 1 && up == 2){ // () 只能在最后一个格子合并 if (x == ex && y == ey){ setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } } else if (left == 2 && up == 1){ // )( 维持原来状态 setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } } else { // 有一个插头 if (left == 0 && up){ aft = hm[cur].item[i].key; if (a[x][y + 1]){ if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } aft = hm[cur].item[i].key; if (a[x + 1][y]){ setplug(aft , y - 1 , up); setplug(aft , y , 0); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } } else if (left && up == 0){ aft = hm[cur].item[i].key; if (a[x + 1][y]){ if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } aft = hm[cur].item[i].key; if (a[x][y + 1]){ setplug(aft , y - 1 , 0); setplug(aft , y , left); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } } } } } void dpblock(int x , int y , int cur){ int left , up; int aft; for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){ aft = hm[cur].item[i].key; left = getplug(hm[cur].item[i].key , y - 1); up = getplug(hm[cur].item[i].key , y); if (left || up) continue; if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } } void output(int code){ for (int i = 0 ; i <= m ; ++i){ int ret = code % 4; code /= 4; if (ret == 1) putchar('('); else if (ret == 2) putchar(')'); else putchar('#'); } } void solve(){ RST(a); for (int i = 1 ; i <= n; ++i){ scanf("%s" , str); for(int j = 1 ; j <= m ; ++j){ a[i][j] = (str[j - 1] == '.'); if (a[i][j]){ ex = i , ey = j; } } } LL ans = 0; int cur = 0; hm[0].init();hm[1].init(); hm[0][0] = 1; for (int i = 1 ; i <= n ; ++i) for (int j = 1 ; j <= m ; ++j){ hm[cur ^ 1].clear(); if (a[i][j]) dpblank(i , j , cur); else dpblock(i , j , cur); cur ^= 1; } for (int i = 0 ; i < hm[cur].L ; ++i){ ans += hm[cur].item[i].val; } printf("%I64d\n" , ans); } int main(){ Case = 0; while(~scanf("%d%d" , &n , &m)) solve(); }
跟上一题几乎一样。还是四进制括号表示法
但是有必须走和不是必须走的格子,改变两下——
1. 不必须走的 没有 left 和 up 插头可以继续扩展,忽略格子
2. 加入 是否形成圈 这个变量。
struct Hashmap{ const static int HASHSIZE = 1e3 + 7; const static int STATUSSIZE = 1e5 + 9; int head[HASHSIZE]; struct hash_item{ int key; LL val; int next; }item[STATUSSIZE + 1]; int L; int getHash(int x){ return x % HASHSIZE; } void init(){ memset(head , -1 , sizeof(head)); L = 0; } void clear(){ for (int i = 0; i < L ; ++i) head[getHash(item[i].key)] = -1; L = 0; } int contains(int x){ for (int i = head[getHash(x)]; i != -1 ; i = item[i].next) if (item[i].key == x) return i; return -1; } void insert(int x){ int tmp = getHash(x); item[L].key = x; item[L].val = 0; item[L].next = head[tmp]; head[tmp] = L++; } LL& operator[] (int x){ int tmp = contains(x); if (tmp == -1){ insert(x); return item[L - 1].val; } else return item[tmp].val; } }hm[2]; const int N = 15; int n , m; int a[N][N]; int ex , ey; char str[N]; int getplug(int cur , int y){ cur >>= 2 * y; int ret = cur & 1; cur >>= 1; ret |= (cur & 1) << 1; return ret; } int getcirlce(int cur){ // 加入连通记录,获取记录 int mm = (m + 1) << 1; return (cur & (1 << mm)) != 0; } void setcircle(int &cur , int iscircle){ // 加入连通记录,改变 int mm = (m + 1) << 1; if (((cur >> mm) & 1) != iscircle) cur ^= 1 << mm; } void shift(int &code){ int iscircle = getcirlce(code); code <<= 2; int mm = (m + 1) << 1; code &= ((1 << mm) - 1); setcircle(code , iscircle); } void setplug(int &cur , int y , int key){ if ( ((cur >> (y << 1)) & 1) ^ (key & 1) ) cur ^= 1 << (y << 1); if ( ((cur >> (y << 1 | 1)) & 1) ^ ((key >> 1) & 1) ) cur ^= 1 << (y << 1 | 1); } void dpblank(int x , int y , int cur){ int left , up; int aft; int circle; for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){ aft = hm[cur].item[i].key; left = getplug(hm[cur].item[i].key , y - 1); up = getplug(hm[cur].item[i].key , y); circle = getcirlce(hm[cur].item[i].key); if (left == 0 && up == 0){ //无插头,新建联通分量 if (a[x + 1][y] && a[x][y + 1]){ setplug(aft , y - 1 , 1); setplug(aft , y , 2); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } aft = hm[cur].item[i].key; if (a[x][y] == 2){ // 如果不是必须走的话就可以不扩展这个格子 if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } } else if (left && up){ // 有两个插头 ! 要删掉上插头和左插头啊 if (left == 1 && up == 1){ // (( 找到下一个对应的 ) 改成 ( int top = 0; for (int j = y ; j <= m ; ++j){ int plug = getplug(hm[cur].item[i].key , j); if (plug == 1) ++top; if (plug == 2) --top; if (top == 0){ setplug(aft , j , 1); break; } } setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } else if (left == 2 && up == 2){ // )) 找到上一个对应的 ( 变成 ) int top = 0; for (int j = y - 1 ; j >= 0 ; --j){ int plug = getplug(hm[cur].item[i].key , j); if (plug == 2) ++top; if (plug == 1) --top; if (top == 0){ setplug(aft , j , 2); break; } } setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } else if (left == 1 && up == 2){ // () 只能在最后一个格子合并 if (!circle){ // 如果没有连通的话加入连通 setplug(aft , y - 1 , 0); setplug(aft , y , 0); setcircle(aft , 1); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } } else if (left == 2 && up == 1){ // )( 维持原来状态 setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } } else { // 有一个插头 if (left == 0 && up){ aft = hm[cur].item[i].key; if (a[x][y + 1]){ if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } aft = hm[cur].item[i].key; if (a[x + 1][y]){ setplug(aft , y - 1 , up); setplug(aft , y , 0); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } } else if (left && up == 0){ aft = hm[cur].item[i].key; if (a[x + 1][y]){ if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } aft = hm[cur].item[i].key; if (a[x][y + 1]){ setplug(aft , y - 1 , 0); setplug(aft , y , left); if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } } } } } void dpblock(int x , int y , int cur){ int left , up; int aft; for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){ aft = hm[cur].item[i].key; left = getplug(hm[cur].item[i].key , y - 1); up = getplug(hm[cur].item[i].key , y); if (left || up) continue; if (y == m) shift(aft); hm[cur ^ 1][aft] += hm[cur].item[i].val; } } void output(int code){ for (int i = 0 ; i <= m ; ++i){ int ret = code % 4; code /= 4; if (ret == 1) putchar('('); else if (ret == 2) putchar(')'); else putchar('#'); } } void solve(){ RD(n , m); RST(a); for (int i = 1 ; i <= n; ++i){ scanf("%s" , str); for(int j = 1 ; j <= m ; ++j){ if (str[j - 1] == '*') a[i][j] = 2; if (str[j - 1] == 'O') a[i][j] = 1; } } LL ans = 0; int cur = 0; hm[0].init();hm[1].init(); hm[0][0] = 1; for (int i = 1 ; i <= n ; ++i) for (int j = 1 ; j <= m ; ++j){ hm[cur ^ 1].clear(); if (a[i][j]) dpblank(i , j , cur); else dpblock(i , j , cur); cur ^= 1; } for (int i = 0 ; i < hm[cur].L ; ++i) { if (getcirlce(hm[cur].item[i].key)) ans += hm[cur].item[i].val; } printf("Case %d: %I64d\n" , ++Case , ans); } int main(){ Case = 0; Rush solve(); }
求单路径的最小分数。喜闻乐见直接套模板啊。
稍微改动的是求分数,val直接改成分数就好了。存在即有分,hashmap里面的状态都是可达的状态。
看下 喜闻乐见 的debug 方式
struct Hashmap{ const static int HASHSIZE = 1e4 + 7; const static int STATUSSIZE = 1e5 + 9; int head[HASHSIZE]; struct hash_item{ int key; int val; // val 值改成最小分数 —— “存在”即有分,不用判断是否状态可达。在 hashmap 里面的状态都可达 int next; }item[STATUSSIZE + 1]; int L; int getHash(int x){ return x % HASHSIZE; } void init(){ memset(head , -1 , sizeof(head)); L = 0; } void clear(){ for (int i = 0; i < L ; ++i) head[getHash(item[i].key)] = -1; L = 0; } int contains(int x){ for (int i = head[getHash(x)]; i != -1 ; i = item[i].next) if (item[i].key == x) return i; return -1; } void insert(int x){ int tmp = getHash(x); item[L].key = x; item[L].val = 0; item[L].next = head[tmp]; head[tmp] = L++; } void set(int x , int y){ int tmp = contains(x); if (tmp == -1){ insert(x); item[L - 1].val = y; } checkMin(item[tmp].val , y); } }hm[2]; const int N = 15; int n , m; int a[N][N]; int ex , ey; char str[N<<1][N<<1]; PII score[N][N]; int getplug(int cur , int y){ cur >>= 2 * y; int ret = cur & 1; cur >>= 1; ret |= (cur & 1) << 1; return ret; } void shift(int &code){ code <<= 2; int mm = (m + 1) << 1; code &= ((1 << mm) - 1); } void setplug(int &cur , int y , int key){ if ( ((cur >> (y << 1)) & 1) ^ (key & 1) ) cur ^= 1 << (y << 1); if ( ((cur >> (y << 1 | 1)) & 1) ^ ((key >> 1) & 1) ) cur ^= 1 << (y << 1 | 1); } void dpblank(int x , int y , int cur){ int left , up; int aft; for (int i = 0 ; i < hm[cur].L ; ++i){ aft = hm[cur].item[i].key; left = getplug(hm[cur].item[i].key , y - 1); up = getplug(hm[cur].item[i].key , y); if (left == 0 && up == 0){ //无插头,新建联通分量 if (a[x + 1][y] && a[x][y + 1]){ setplug(aft , y - 1 , 1); setplug(aft , y , 2); if (y == m) shift(aft); hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].fi + score[x][y].se); } } else if (left && up){ // 有两个插头 ! 要删掉上插头和左插头啊 if (left == 1 && up == 1){ // (( 找到下一个对应的 ) 改成 ( int top = 0; for (int j = y ; j <= m ; ++j){ int plug = getplug(hm[cur].item[i].key , j); if (plug == 1) ++top; if (plug == 2) --top; if (top == 0){ setplug(aft , j , 1); break; } } setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); // hm[cur ^ 1][aft] += hm[cur].item[i].val; hm[cur ^ 1].set(aft , hm[cur].item[i].val); } else if (left == 2 && up == 2){ // )) 找到上一个对应的 ( 变成 ) int top = 0; for (int j = y - 1 ; j >= 0 ; --j){ int plug = getplug(hm[cur].item[i].key , j); if (plug == 2) ++top; if (plug == 1) --top; if (top == 0){ setplug(aft , j , 2); break; } } setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); // hm[cur ^ 1][aft] += hm[cur].item[i].val; hm[cur ^ 1].set(aft , hm[cur].item[i].val); } else if (left == 1 && up == 2){ // () 只能在最后一个格子合并 if (x == ex && y == ey){ // 如果没有连通的话加入连通 setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); // hm[cur ^ 1][aft] += hm[cur].item[i].val; hm[cur ^ 1].set(aft , hm[cur].item[i].val); } } else if (left == 2 && up == 1){ // )( 维持原来状态 setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); // hm[cur ^ 1][aft] += hm[cur].item[i].val; hm[cur ^ 1].set(aft , hm[cur].item[i].val); } } else { // 有一个插头 if (left == 0 && up){ aft = hm[cur].item[i].key; if (a[x][y + 1]){ if (y == m) shift(aft); //hm[cur ^ 1][aft] += hm[cur].item[i].val; hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].se); } aft = hm[cur].item[i].key; if (a[x + 1][y]){ setplug(aft , y - 1 , up); setplug(aft , y , 0); if (y == m) shift(aft); //hm[cur ^ 1][aft] += hm[cur].item[i].val; hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].fi); } } else if (left && up == 0){ aft = hm[cur].item[i].key; if (a[x + 1][y]){ if (y == m) shift(aft); // hm[cur ^ 1][aft] += hm[cur].item[i].val; hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].fi); } aft = hm[cur].item[i].key; if (a[x][y + 1]){ setplug(aft , y - 1 , 0); setplug(aft , y , left); if (y == m) shift(aft); // hm[cur ^ 1][aft] += hm[cur].item[i].val; hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].se); } } } } } void dpblock(int x , int y , int cur){ int left , up; int aft; for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){ aft = hm[cur].item[i].key; left = getplug(hm[cur].item[i].key , y - 1); up = getplug(hm[cur].item[i].key , y); if (left || up) continue; if (y == m) shift(aft); // hm[cur ^ 1][aft] += hm[cur].item[i].val; hm[cur ^ 1].set(aft , hm[cur].item[i].val); } } void output(int code){ for (int i = 0 ; i <= m ; ++i){ int ret = code % 4; code /= 4; if (ret == 1) putchar('('); else if (ret == 2) putchar(')'); else putchar('#'); } } void solve(){ RD(n , m); int line = 0; gets(str[0]); for (int i = 0 ; i < 2 * n + 1 ; ++i){ gets(str[i]); if (!i) continue; if (i & 1) line++; if (i & 1){ for (int j = 1 ; j < m ; ++j) score[line][j].se = str[i][j * 2] - '0'; } else{ for (int j = 1 ; j <= m ; ++j) score[line][j].fi = str[i][j * 2 - 1] - '0'; } } RST(a); ex = n;ey = m; for (int i = 1 ; i <= n; ++i){ for(int j = 1 ; j <= m ; ++j){ a[i][j] = 1; } } int ans = INF; int cur = 0; hm[0].init();hm[1].init(); hm[0].set(0 , 0); for (int i = 1 ; i <= n ; ++i) for (int j = 1 ; j <= m ; ++j){ /** 比较喜闻乐见的 debug 方式 */ // printf("Before %d %d\n" , i , j); // for (int k = 0 ; k < hm[cur].L ; ++k){ // output(hm[cur].item[k].key); // printf(":%d\t" , hm[cur].item[k].val); // } // puts(""); hm[cur ^ 1].clear(); dpblank(i , j , cur); cur ^= 1; // printf("After %d %d\n" , i , j); // for (int k = 0 ; k < hm[cur].L ; ++k){ // output(hm[cur].item[k].key); // printf(":%d\t" , hm[cur].item[k].val); // } // puts(""); } for (int i = 0 ; i < hm[cur].L ; ++i) checkMin(ans , hm[cur].item[i].val); printf("%d\n" , ans); } int main(){ Case = 0; Rush solve(); }
在有障碍的前提下,从左上走到右下的最小花费。
解法1:
加两行——
#.. ...
#.. ... .#. ...
3进制正式变成 4 进制——独立插头
struct Hashmap{ const static int HASHSIZE = 681; const static int STATUSSIZE = 1e4 + 9; int head[HASHSIZE]; struct hash_item{ int key; LL val; int next; }item[STATUSSIZE + 1]; int L; int getHash(int x){ return x % HASHSIZE; } void init(){ memset(head , -1 , sizeof(head)); L = 0; } void clear(){ init();return; for (int i = 0; i < L ; ++i) head[getHash(item[i].key)] = -1; L = 0; } int contains(int x){ for (int i = head[getHash(x)]; i != -1 ; i = item[i].next) if (item[i].key == x) return i; return -1; } void insert(int x){ int tmp = getHash(x); item[L].key = x; item[L].val = 0; item[L].next = head[tmp]; head[tmp] = L++; } LL& operator[] (int x){ int tmp = contains(x); if (tmp == -1){ insert(x); return item[L - 1].val; } else return item[tmp].val; } }hm[2]; const int N = 15; int n , m; int code[N] , a[N][N]; int ex , ey; char str[N]; void shift(int &code){ code <<= 2; int mm = (m + 1) << 1; code &= ((1 << mm) - 1); } int getplug(int cur , int y){ cur >>= 2 * y; int ret = cur & 3; return ret; } void setplug(int &cur , int y , int key){ if ( ((cur >> (y << 1)) & 1) ^ (key & 1) ) cur ^= 1 << (y << 1); if ( ((cur >> (y << 1 | 1)) & 1) ^ ((key >> 1) & 1) ) cur ^= 1 << (y << 1 | 1); } bool canbeSinglePlug(int x , int y){ if (x == n) return y == 1 || y == m; return false; } void UPD(LL &x , LL y){ x += y; } void dpblank(int x , int y , int cur){ int left , up; int aft; for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){ aft = hm[cur].item[i].key; left = getplug(hm[cur].item[i].key , y - 1); up = getplug(hm[cur].item[i].key , y); if (left == 0 && up == 0){ //无插头,新建联通分量 if (a[x + 1][y] && a[x][y + 1]){ setplug(aft , y - 1 , 1); setplug(aft , y , 2); if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } if (canbeSinglePlug(x , y)){ // 如果能形成独立插头 if (a[x + 1][y]){ aft = hm[cur].item[i].key; setplug(aft , y - 1 , 3); setplug(aft , y , 0); if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } if (a[x][y + 1]){ aft = hm[cur].item[i].key; setplug(aft , y - 1 , 0); setplug(aft , y , 3); if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } } } else if (left && up){ // 有两个插头 ! 要删掉上插头和左插头啊 if (left == 3 && up == 3){ // 如果都是独立插头,那么只能在最后一个格子里面合并 if (x == ex && y == ey){ setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } } else if (left == 3 || up == 3){ // 如果有一个 独立插头那么,将对应的插头改为独立插头 int other = left + up - 3; if (other == 1){ int top = 1; for (int j = y + 1; j <= m ; ++j){ int plug = getplug(hm[cur].item[i].key , j); if (plug == 1) ++top; if (plug == 2) --top; if (top == 0){ setplug(aft , j , 3); break; } } setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } else if (other == 2){ int top = 1; for (int j = y - 2 ; j >= 0 ; --j){ int plug = getplug(hm[cur].item[i].key , j); if (plug == 2) ++top; if (plug == 1) --top; if (top == 0){ setplug(aft , j , 3); break; } } setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } } else if (left == 1 && up == 1){ // (( 找到下一个对应的 ) 改成 ( int top = 0; for (int j = y ; j <= m ; ++j){ int plug = getplug(hm[cur].item[i].key , j); if (plug == 1) ++top; if (plug == 2) --top; if (top == 0){ setplug(aft , j , 1); break; } } setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } else if (left == 2 && up == 2){ // )) 找到上一个对应的 ( 变成 ) int top = 0; for (int j = y - 1 ; j >= 0 ; --j){ int plug = getplug(hm[cur].item[i].key , j); if (plug == 2) ++top; if (plug == 1) --top; if (top == 0){ setplug(aft , j , 2); break; } } setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } else if (left == 1 && up == 2){ // () 只能在最后一个格子合并 // if (x == ex && y == ey){ // 不可能发生 // setplug(aft , y - 1 , 0); // setplug(aft , y , 0); // if (y == m) shift(aft); // hm[cur ^ 1][aft] += hm[cur].item[i].val; // } } else if (left == 2 && up == 1){ // )( 维持原来状态 setplug(aft , y - 1 , 0); setplug(aft , y , 0); if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } } else { // 有一个插头 if (left + up == 3){ // 如果只有一个独立插头 if (x == ex && y == ey){ //那么可以在最后一个非障碍格子中成为另一端 if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } else{ // 或者用下插头 或者 有插头 延续独立插头 aft = hm[cur].item[i].key; if(a[x + 1][y]){ setplug(aft , y - 1 , 3); setplug(aft , y , 0); if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } aft = hm[cur].item[i].key; if(a[x][y + 1]){ setplug(aft , y - 1 , 0); setplug(aft , y , 3); if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } } } else{ if (canbeSinglePlug(x , y)){ // 将当前插头封住,另一端成为独立插头 int thisplug = left + up; setplug(aft , y - 1 , 0); setplug(aft, y , 0); if (thisplug == 1){ int top = 1; for (int j = y + 1 ; j <= m ; ++j){ int plug = getplug(hm[cur].item[i].key , j); if (plug == 1) ++top; if (plug == 2) --top; if (top == 0){ setplug(aft , j , 3); break; } } } else if (thisplug == 2){ int top = 1; for (int j = y - 2 ; j <= m ; ++j){ int plug = getplug(hm[cur].item[i].key , j); if (plug == 2) ++top; if (plug == 1) --top; if (top == 0){ setplug(aft , j , 3); break; } } } if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } aft = hm[cur].item[i].key; if (left == 0 && up){ aft = hm[cur].item[i].key; if (a[x][y + 1]){ if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } aft = hm[cur].item[i].key; if (a[x + 1][y]){ setplug(aft , y - 1 , up); setplug(aft , y , 0); if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } } else if (left && up == 0){ aft = hm[cur].item[i].key; if (a[x + 1][y]){ if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } aft = hm[cur].item[i].key; if (a[x][y + 1]){ setplug(aft , y - 1 , 0); setplug(aft , y , left); if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } } } } } } void dpblock(int x , int y , int cur){ int left , up; int aft; for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){ aft = hm[cur].item[i].key; left = getplug(hm[cur].item[i].key , y - 1); up = getplug(hm[cur].item[i].key , y); if (left || up) continue; if (y == m) shift(aft); UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val); } } void output(int code){ for (int i = 0 ; i <= m ; ++i){ int ret = code % 4; code /= 4; if (ret == 1) putchar('('); else if (ret == 2) putchar(')'); else if (ret == 3) putchar('|'); else putchar('#'); } } void solve(){ RST(a); for (int i = 1 ; i <= n; ++i){ scanf("%s" , str); for(int j = 1 ; j <= m ; ++j){ a[i][j] = (str[j - 1] == '.'); if (a[i][j]){ ex = i , ey = j; } } } ex = n , ey = m; LL ans = 0; int cur = 0; hm[0].init();hm[1].init(); hm[0][0] = 1; for (int i = 1 ; i <= n ; ++i) for (int j = 1 ; j <= m ; ++j){ hm[cur ^ 1].clear(); if (a[i][j]) dpblank(i , j , cur); else dpblock(i , j , cur); cur ^= 1; // printf("%d %d:\n" , i , j); // debug 方法,输出 插头形式 // for (int k = 0 ; k < hm[cur].L ; ++k){ // output(hm[cur].item[k].key);printf(":%lld\t" , hm[cur].item[k].val); // } // puts(""); } for (int i = 0 ; i < hm[cur].L ; ++i){ ans += hm[cur].item[i].val; } printf("%lld\n" , ans); } int main(){ Case = 0; while(~scanf("%d%d" , &n , &m) && n && m) solve(); }