https://vjudge.net/problem/URAL-1519
插头dp。。。
终于A掉了。。。抄了一个板子。。。
看那个ccy大神的博客 写的非常好。。。
讲几个问题:插头就是线穿过格子的边缘 左插头就是竖着的轮廓线左边 右插头就是竖着的轮廓线右边。。。我好想没用到这个概念。。。
然后就是各种分类讨论。。。
dp初值:dp[0][0]=1 第0行状态为0的方案数为1
这个东西还是抄一下吧。。。
hash版:仿写的 跑的很快 那个hash不是很懂
#include<bits/stdc++.h> using namespace std; typedef unsigned long long ll; const int N = 199917, M = 20, lim = 199917; int n, m, k, endx, endy; int a[M][M], tot[2]; //每种方案的总和//存哈希值 ll ans; ll Hash[N], state[2][N], sum[2][N], bin[M]; void hash(ll s, ll delta) { //把状态哈希成数值 int pos = s % lim; while(Hash[pos]) { if(state[k][Hash[pos]] == s) { sum[k][Hash[pos]] += delta; return; } ++pos; if(pos == lim) pos = 0; } ++tot[k]; Hash[pos] = tot[k]; state[k][tot[k]] = s; sum[k][tot[k]] = delta; } void solve() { tot[0] = sum[0][1] = 1; for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { // printf("i=%d j=%d ", i, j); k ^= 1; memset(Hash, 0, sizeof(Hash)); memset(sum[k], 0, sizeof(sum[k])); memset(state[k], 0, sizeof(state[k])); tot[k] = 0; for(int t = 1; t <= tot[k ^ 1]; ++t) { ll s = state[k ^ 1][t]; int p = (s >> bin[j - 1]) % 4; int q = (s >> bin[j]) % 4; ll delta = sum[k ^ 1][t]; // printf("s=%d p=%d q=%d delta=%d ", s, p, q, delta); if(!a[i][j]) { //障碍物 if(!p && !q) hash(s, delta); continue; } if(!p && !q) { if(a[i][j + 1] && a[i + 1][j]) { //能不能伸出插头 // printf("bin[j]=%d ", bin[j]); s = s + (1 << bin[j - 1]) + (1 << bin[j]) * 2; hash(s, delta); } continue; } if(!p && q) { //有一个插头 if(a[i][j + 1]) hash(s, delta); if(a[i + 1][j]) { s = s + q * (1 << bin[j - 1]) - q * (1 << bin[j]); hash(s, delta); } continue; } if(p && !q) { if(a[i + 1][j]) hash(s, delta); if(a[i][j + 1]) { s = s - p * (1 << bin[j - 1]) + p * (1 << bin[j]); hash(s, delta); } continue; } if(p == 1 && q == 1) { int cnt = 1; for(int v = j + 1; v <= m; ++v) { int t = (s >> bin[v]) % 4; if(t == 1) ++cnt; else if(t == 2) --cnt; if(cnt == 0) { // printf("v1=%d ", v); s -= (1 << bin[v]); break; } } s -= p * (1 << bin[j - 1]) + q * (1 << bin[j]); hash(s, delta); continue; } if(p == 2 && q == 2) { int cnt = 1; for(int v = j - 2; v; --v) { int t = (s >> bin[v]) % 4; if(t == 2) ++cnt; else if(t == 1) --cnt; if(cnt == 0) { // printf("v2=%d ", v); s += (1 << bin[v]); break; } } s -= 2 * (1 << bin[j - 1]) + 2 * (1 << bin[j]); hash(s, delta); continue; } if(p == 2 && q == 1) { s -= 2 * (1 << bin[j - 1]) + (1 << bin[j]); hash(s, delta); continue; } if(p == 1 && q == 2) { // printf("delta=%d ", delta); if(i == endx && j == endy) ans += delta; continue; } } } for(int i = 1; i <= tot[k]; ++i) state[k][i] <<= 2; } } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++i) { //每个括号用两位表示 char s[M]; scanf("%s", s + 1); for(int j = 1; j <= m; ++j) { a[i][j] = (s[j] == '.'); if(s[j] == '.') { endx = i; endy = j; } } } for(int i = 1; i <= max(n, m); ++i) bin[i] = i << 1; solve(); printf("%llu ", ans); return 0; }
set版:set直接hash判重 但是跑的很慢
#include<bits/stdc++.h> using namespace std; typedef unsigned long long ll; const int N = 600010, M = 20; int n, m, k, endx, endy; int a[M][M]; ll bin[M], st[N]; //每种方案的总和 map<ll, ll> sum[2]; set<ll> s[2]; //存哈希值 ll ans; void hash(ll state, ll delta) { //把状态哈希成数值 if(s[k].count(state)) { sum[k][state] += delta; return; } s[k].insert(state); sum[k][state] = delta; } void solve() { sum[0][0] = 1; s[0].insert(0); for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { // printf("i=%d j=%d ", i, j); k ^= 1; sum[k].clear(); s[k].clear(); for(set<ll>::iterator it = s[k ^ 1].begin(); it != s[k ^ 1].end(); ++it) { ll s = *it; int p = (s >> bin[j - 1]) & 3; int q = (s >> bin[j]) & 3; ll delta; if(j == 1) delta = sum[k ^ 1][*it >> 2]; else delta = sum[k ^ 1][*it]; // printf("s=%d p=%d q=%d delta=%d ", s, p, q, delta); if(!a[i][j]) { //障碍物 if(!p && !q) hash(s, delta); continue; } if(!p && !q) { if(a[i][j + 1] && a[i + 1][j]) { //能不能伸出插头 s = s + (1 << bin[j - 1]) + (1 << bin[j]) * 2; hash(s, delta); } continue; } if(!p && q) { //有一个插头 if(a[i][j + 1]) hash(s, delta); if(a[i + 1][j]) { s = s + q * (1 << bin[j - 1]) - q * (1 << bin[j]); hash(s, delta); } continue; } if(p && !q) { if(a[i + 1][j]) hash(s, delta); if(a[i][j + 1]) { s = s - p * (1 << bin[j - 1]) + p * (1 << bin[j]); hash(s, delta); } continue; } if(p == 1 && q == 1) { int cnt = 1; for(int v = j + 1; v <= m; ++v) { int t = (s >> bin[v]) & 3; if(t == 1) ++cnt; else if(t == 2) --cnt; if(cnt == 0) { s -= (1 << bin[v]); break; } } s -= p * (1 << bin[j - 1]) + q * (1 << bin[j]); hash(s, delta); continue; } if(p == 2 && q == 2) { int cnt = 1; for(int v = j - 2; v; --v) { int t = (s >> bin[v]) & 3; if(t == 2) ++cnt; else if(t == 1) --cnt; if(cnt == 0) { s += 1 << bin[v]; break; } } s -= 2 * (1 << bin[j - 1]) + 2 * (1 << bin[j]); hash(s, delta); continue; } if(p == 2 && q == 1) { s -= 2 * (1 << bin[j - 1]) + (1 << bin[j]); hash(s, delta); continue; } if(p == 1 && q == 2) { if(i == endx && j == endy) ans += delta; continue; } } } int top = 0; for(set<ll>::iterator it = s[k].begin(); it != s[k].end(); ++it) st[++top] = ((*it) << 2); s[k].clear(); while(top) { s[k].insert(st[top]); --top; } } } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++i) { //每个括号用两位表示 char s[M]; scanf("%s", s + 1); for(int j = 1; j <= m; ++j) { a[i][j] = (s[j] == '.'); if(s[j] == '.') { endx = i; endy = j; } } } for(int i = 1; i <= max(n, m); ++i) bin[i] = i << 1; solve(); printf("%llu ", ans); return 0; }