1. 程式人生 > >bzoj1814 Ural 1519 Formula 1 插頭dp

bzoj1814 Ural 1519 Formula 1 插頭dp

Description


一個 n * m 的棋盤,有的格子存在障礙,求經過所有非障礙格子的哈密頓迴路個數

2 ≤ N, M ≤ 12

Solution


插頭dp入門題。。

我們設f[i,j,S]表示遞推到第i行第j列,輪廓線上插頭連通性狀態為S的方案數。所謂輪廓線就是已經dp過格子下邊界加上當前格子的右邊界組成的一條折線。所謂插頭就是路徑在輪廓線上的走向。
我們用三進製表示輪廓線狀態,0表示無插頭,1和2分別表示左右括號(一條路徑的左右端點)。轉移的時候分九種情況討論一下就可以了。

出於不知道的原因我的程式碼跑不過bzoj,跑過了timus

Code


#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)

typedef long long LL;
const int N=41836;

int rc[14][14],bin[16],rec[N],rnk[1593229],n,m,tot;

LL f[13][13][N];

char str[13];

inline int get(int S,int p) {
	return (S/bin[p])%3;
}

inline
void dfs(int dep,int sum,int S) { if (sum<0||sum+dep-1>m) return ; if (dep>m) { rec[++tot]=S,rnk[S]=tot; return ; } dfs(dep+1,sum,S); dfs(dep+1,sum+1,S+bin[dep]); dfs(dep+1,sum-1,S+2*bin[dep]); } inline int left(int S,int i) { int sum=0; for (;~i;--i) { int x=get(S,i); if (x==
1) --sum; else if (x==2) ++sum; if (!sum) return bin[i]; } return -1; } inline int righ(int S,int i) { int sum=0; for (;i<=m;++i) { int x=get(S,i); if (x==1) ++sum; else if (x==2) --sum; if (!sum) return bin[i]; } return -1; } int main(void) { freopen("data.in","r",stdin); bin[0]=1; rep(i,1,15) bin[i]=bin[i-1]*3; int tn,tm; LL ans=0; scanf("%d%d",&n,&m); rep(i,1,n) { scanf("%s",str+1); rep(j,1,m) if (str[j]=='.') { rc[i][j]=1; tn=i,tm=j; } } dfs(0,0,0); f[1][0][1]=1; rep(i,1,n) { rep(j,1,m) rep(k,1,tot) { int S=rec[k],p=get(S,j-1),q=get(S,j); LL tmp=f[i][j-1][k]; if (!rc[i][j]) { if (!p&&!q) f[i][j][k]+=tmp; } else { if (!p&&!q&&rc[i+1][j]&&rc[i][j+1]) f[i][j][rnk[S+bin[j-1]+2*bin[j]]]+=tmp; if (!p&&q) { if (rc[i][j+1]) f[i][j][k]+=tmp; if (rc[i+1][j]) f[i][j][rnk[S-q*(bin[j]-bin[j-1])]]+=tmp; } if (p&&!q) { if (rc[i+1][j]) f[i][j][k]+=tmp; if (rc[i][j+1]) f[i][j][rnk[S-p*(bin[j-1]-bin[j])]]+=tmp; } if (p==1&&q==1) f[i][j][rnk[S-bin[j-1]-bin[j]-righ(S,j)]]+=tmp; else if (p==2&&q==2) f[i][j][rnk[S-2*(bin[j-1]+bin[j])+left(S,j-1)]]+=tmp; else if (p==2&&q==1) f[i][j][rnk[S-2*bin[j-1]-bin[j]]]+=tmp; else if (p==1&&q==2&&i==tn&&j==tm) ans+=tmp; } } if (i!=n) rep(k,1,tot) if (rec[k]%3==0) f[i+1][0][k]+=f[i][m][rnk[rec[k]/3]]; } printf("%lld\n", ans); return 0; }