【bzoj1814】Ural 1519 Formula 1 插頭dp
題目描述
一個 m * n 的棋盤,有的格子存在障礙,求經過所有非障礙格子的哈密頓回路個數。
輸入
The first line contains the integer numbers N and M (2 ≤ N, M ≤ 12). Each of the next N lines contains M characters, which are the corresponding cells of the rectangle. Character "." (full stop) means a cell, where a segment of the race circuit should be built, and character "*" (asterisk) - a cell, where a gopher hole is located.
輸出
You should output the desired number of ways. It is guaranteed, that it does not exceed 2^63-1.
樣例輸入
4 4
**..
....
....
....
樣例輸出
2
題解
插頭dp板子題
具體講解可以參考 陳丹琦《基於連通性狀態壓縮的動態規劃問題》 以及 Dalao博客 。
我的代碼中使用了三進制狀態,先使用dfs預處理出所有合法的廣義括號序列,用0表示沒有插頭,1表示左括號插頭,2表示右括號插頭。處理好狀態與編號的對應關系後進行dp,復雜度就只與合法狀態數有關了。
時間復雜度 $O(合法狀態數·nm^2)$ ,經計算合法狀態數不超過42000。而實際上這個時間復雜度遠遠達不到上限,因為只有兩個插頭是雙左括號或雙右括號時才會產生最後的m,且這個m也是不滿的。因此可以過。
註意需要long long。
#include <cstdio> #include <algorithm> using namespace std; int m , a[14][14] , v[42000] , w[1600000] , tot , b[14]; long long f[13][13][42000]; char str[14]; void dfs(int p , int c , int now) { if(c < 0 || c > m + 1 - p + 1) return; if(p > m + 1) { v[++tot] = now , w[now] = tot; return; } dfs(p + 1 , c , now); dfs(p + 1 , c + 1 , now + b[p - 1]); dfs(p + 1 , c - 1 , now + 2 * b[p - 1]); } inline int left(int v , int p) { int i , c = 0; for(i = p ; ~i ; i -- ) { if(v / b[i] % 3 == 1) c -- ; if(v / b[i] % 3 == 2) c ++ ; if(!c) return i; } return -1; } inline int right(int v , int p) { int i , c = 0; for(i = p ; i <= m ; i ++ ) { if(v / b[i] % 3 == 2) c -- ; if(v / b[i] % 3 == 1) c ++ ; if(!c) return i; } return -1; } int main() { int n , i , j , k , nn , mm , p , q; long long ans = 0; scanf("%d%d" , &n , &m); for(i = 1 ; i <= n ; i ++ ) { scanf("%s" , str + 1); for(j = 1 ; j <= m ; j ++ ) if(str[j] == ‘.‘) a[i][j] = 1 , nn = i , mm = j; } b[0] = 1; for(i = 1 ; i <= m ; i ++ ) b[i] = b[i - 1] * 3; dfs(1 , 0 , 0); f[1][0][1] = 1; for(i = 1 ; i <= n ; i ++ ) { for(j = 1 ; j <= m ; j ++ ) { for(k = 1 ; k <= tot ; k ++ ) { p = v[k] / b[j - 1] % 3 , q = v[k] / b[j] % 3; if(!a[i][j]) { if(!p && !q) f[i][j][k] += f[i][j - 1][k]; } else { if(!p && !q && a[i][j + 1] && a[i + 1][j]) f[i][j][w[v[k] + b[j - 1] + 2 * b[j]]] += f[i][j - 1][k]; if(!p && q) { if(a[i][j + 1]) f[i][j][k] += f[i][j - 1][k]; if(a[i + 1][j]) f[i][j][w[v[k] + q * (b[j - 1] - b[j])]] += f[i][j - 1][k]; } if(p && !q) { if(a[i + 1][j]) f[i][j][k] += f[i][j - 1][k]; if(a[i][j + 1]) f[i][j][w[v[k] + p * (b[j] - b[j - 1])]] += f[i][j - 1][k]; } if(p == 1 && q == 1) f[i][j][w[v[k] - b[j - 1] - b[j] - b[right(v[k] , j)]]] += f[i][j - 1][k]; if(p == 2 && q == 2) f[i][j][w[v[k] - 2 * b[j - 1] - 2 * b[j] + b[left(v[k] , j - 1)]]] += f[i][j - 1][k]; if(p == 2 && q == 1) f[i][j][w[v[k] - 2 * b[j - 1] - b[j]]] += f[i][j - 1][k]; if(p == 1 && q == 2 && i == nn && j == mm) ans += f[i][j - 1][k]; } } } if(i != n) for(k = 1 ; k <= tot ; k ++ ) if(v[k] % 3 == 0) f[i + 1][0][k] += f[i][m][w[v[k] / 3]]; } printf("%lld\n" , ans); return 0; }
【bzoj1814】Ural 1519 Formula 1 插頭dp