题意:给定n*m的带障碍格子图,求从左下角走到右下角的哈密顿路的总数。
题解:更进一步的插头DP,主要解法可以参照我的上篇日志:http://blog.csdn.net/tmeteorj/article/details/8635090。
改动之处在于单向插头,上篇中用01和10分别代表左右括号,这道题则需要加11作为单向括号(因为它在括号序列状态中是没有与之匹配的括号的)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX=10007;
typedef long long LL;
struct HT
{
int head,hash[MAX],nxt[MAX];
LL cnt[MAX];
void init()
{
head=-1;
memset(hash,-1,sizeof(hash));
memset(nxt,-1,sizeof(nxt));
memset(cnt,0,sizeof(cnt));
}
void insert(int st,LL ct)
{
LL pos=st%MAX;
LL ad=1;
while(hash[pos]!=st&&hash[pos]!=-1)
{
pos+=ad*ad;
ad++;
if(pos>=MAX)pos%=MAX;
}
if(hash[pos]==-1)
{
hash[pos]=st;
cnt[pos]=ct;
nxt[pos]=head;
head=pos;
}
else
cnt[pos]+=ct;
}
} dp[2];
int n,m;
char mp[14][14];
int findright(int st,int pos)
{
int tp,p=pos;
for(int dep=1; dep!=0; p+=1)
{
tp=((st>>((m-p+1)*2))&3)%4;
switch(tp)
{
case 0:
break;
case 1:
dep++;
break;
case 2:
dep--;
break;
}
if(dep==0)
break;
}
return 3<<((m-p+1)*2);
}
int findleft(int st,int pos)
{
int tp,p=pos;
for(int dep=1; dep!=0; p-=1)
{
tp=((st>>((m-p+1)*2))&3)%4;
switch(tp)
{
case 0:
break;
case 1:
dep--;
break;
case 2:
dep++;
break;
}
if(dep==0)
break;
}
return 3<<((m-p+1)*2);
}
LL getans(int fg)
{
LL pos=0,ad=1;
while(dp[fg].hash[pos]!=0&&dp[fg].hash[pos]!=-1)
{
pos+=ad*ad;
ad++;
if(pos>=MAX)pos%=MAX;
}
if(dp[fg].hash[pos]==-1)
{
return 0ll;
}
else
return dp[fg].cnt[pos];
}
int main()
{
while(scanf("%d%d",&n,&m),n||m)
{
for(int i=1; i<=n; i++)scanf(" %s",mp[i]+1);
int fg1=1,fg2,ex,ey;
fg1=0,fg2=1;
dp[fg2].init();
dp[fg2].insert(0,1ll);
for(int i=1; i<=n; i++)
{
fg1=!fg1;
fg2=!fg2;
dp[fg2].init();
for(int tp=dp[fg1].head; tp!=-1; tp=dp[fg1].nxt[tp])
{
if(dp[fg1].hash[tp]&3)
continue;
dp[fg2].insert(dp[fg1].hash[tp]>>2,dp[fg1].cnt[tp]);
}
for(int j=0; j<m; j++)
{
fg1=!fg1;
fg2=!fg2;
dp[fg2].init();
int a=3<<(2*(m-j)),b=3<<(2*(m-j-1));
for(int pos=dp[fg1].head; pos!=-1; pos=dp[fg1].nxt[pos])
{
int st=dp[fg1].hash[pos];
LL ct=dp[fg1].cnt[pos];
int x=((st&a)>>(2*(m-j)))%4,y=((st&b)>>(2*(m-j-1)))%4;
if(i==n)
{
if(j==0)
{
if(y)
dp[fg2].insert(st&(~b)|findright(st,j+3),ct);
else
dp[fg2].insert(st|b,ct);
continue;
}
else if(j==m-1)
{
if((x==3||y==3)&(x!=3||y!=3))
dp[fg2].insert(st&(~a)&(~b),ct);
continue;
}
}
if(mp[i][j+1]=='#')
{
if(x||y)
continue;
dp[fg2].insert(st,ct);
}
else if(x)
{
if(y)
{
if(x==1&&y==1)
dp[fg2].insert((st&(~a)&(~b))^findright(st,j+3),ct);
else if(x==2&&y==1)
dp[fg2].insert(st&(~a)&(~b),ct);
else if(x==2&&y==2)
dp[fg2].insert((st&(~a)&(~b))^findleft(st,j),ct);
else if(x==3)
dp[fg2].insert((st&(~a)&(~b))|findright(st,j+3),ct);
else if(y==3)
dp[fg2].insert((st&(~a)&(~b))|findleft(st,j),ct);
}
else
{
dp[fg2].insert(st,ct);
dp[fg2].insert(st&(~a)|(x<<(2*(m-j-1))),ct);
}
}
else if(y)
{
dp[fg2].insert(st,ct);
dp[fg2].insert(st&(~b)|(y<<(2*(m-j))),ct);
}
else
dp[fg2].insert(st|(1<<(2*(m-j)))|(2<<(2*(m-j-1))),ct);
}
}
}
printf("%lld\n",getans(fg2));
}
return 0;
}