1. 程式人生 > >URAL - 1519 Formula 1

URAL - 1519 Formula 1

題面

題意

給出一張網格圖,用一條哈密頓迴路覆蓋它的所有格子,問有幾種方案。

做法

這道題與HDU - 1693 Eat the Trees的區別在於此題只有一條迴路,因此dp方法有所不同。
同樣是插頭dp,可以發現對於每一條合法的迴路,沿輪廓線將其切成兩部分後,輪廓線上面的部分是多個聯通塊,且每個聯通塊與輪廓線恰好有兩個交點,可以用括號序列來維護這兩個交點,然後逐格遞推時分情況轉移即可,但因為狀態總數為 O ( m

n 3 n + 1 )
O(m*n*3^{n+1})
,所以在轉移時只要記錄方案數非零的狀態轉移即可

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define ll long long
#define N 15
#define M 1600000
using namespace std;

ll m,n,dp[2][M],san[N],li,lj,ans;
char str[N];
bool
mm[N][N],in[M],now,cur; vector<ll>have[2]; inline ll get(ll u,ll v){return u/san[v-1]%3;} inline ll chg(ll u,ll v,ll w){return u+(w-get(u,v))*san[v-1];} inline void add(ll u,ll v) { if(!dp[now][u]) have[now].push_back(u); dp[now][u]+=v; } int main() { ll i,j,k,kk,t,l,p,q,jb; cin>>m>>n; san[0]=1; for(i=1;i<=n+1;i++) san[i]=san[i-1]*3; for(i=1;i<=m;i++) { scanf("%s",str+1); for(j=1;j<=n;j++) { if(str[j]=='*') mm[i][j]=1; else li=i,lj=j; } mm[i][0]=mm[i][n+1]=1; } for(i=0;i<=n+1;i++) mm[0][i]=mm[m+1][i]=1; now=1; add(0,1); for(i=1;i<=m;i++) { for(j=1;j<=n;j++) { swap(now,cur); have[now].clear(); for(kk=0;kk<have[cur].size();kk++) { k=have[cur][kk]; p=get(k,j),q=get(k,j+1); if(mm[i][j]) { if(!p&&!q) add(k,dp[cur][k]); } else if(!p&&!q) { if(!mm[i+1][j] && !mm[i][j+1]) { t=chg(k,j,1),t=chg(t,j+1,2); add(t,dp[cur][k]); } } else if(!p||!q) { t=chg(k,j,0),t=chg(t,j+1,0); if(!mm[i][j+1]) add(chg(t,j+1,p+q),dp[cur][k]); if(!mm[i+1][j]) add(chg(t,j,p+q),dp[cur][k]); } else if(p==2&&q==1) { t=chg(k,j,0),t=chg(t,j+1,0); add(t,dp[cur][k]); } else if(p==1&&q==1) { t=chg(k,j,0),t=chg(t,j+1,0),jb=0; for(l=j+2;;l++) { if(get(k,l)==1) jb++; else if(jb&&get(k,l)==2) jb--; else if(!jb&&get(k,l)==2) break; } t=chg(t,l,1); add(t,dp[cur][k]); } else if(p==2&&q==2) { t=chg(k,j,0),t=chg(t,j+1,0),jb=0; for(l=j-1;;l--) { if(get(k,l)==2) jb++; else if(jb&&get(k,l)==1) jb--; else if(!jb&&get(k,l)==1) break; } t=chg(t,l,2); add(t,dp[cur][k]); } else if(i==li&&j==lj) ans+=dp[cur][k]; dp[cur][k]=0; } } swap(now,cur); have[now].clear(); for(kk=0;kk<have[cur].size();kk++) { k=have[cur][kk]; add(k*3,dp[cur][k]); dp[cur][k]=0; } } cout<<ans; }