【BZOJ1814】Ural 1519 Formula 1 插头DP

时间:2023-03-08 17:10:33

【BZOJ1814】Ural 1519 Formula 1

题意:一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数。(n,m<=12)

题解:插头DP板子题,刷板子,附带题解链接

如何存放状态呢?可以采用hash,我们的hash表形如一个队列,每次新加入一个状态时,就沿着这个状态在队列中对应的hash值不断向后找,直到找到这个状态或者发现一个空位为止。

本题我的状态采用了4进制表示。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int limit=99991;
int n,m,k,tot[2],nn,mm;
bool v[20][20];
char str[20];
ll tag,ans;
int hs[limit],state[2][limit];
ll dp[2][limit];
inline void upd(ll S)
{
register int pos=S%limit;
while(hs[pos])
{
if(state[k][hs[pos]]==S)
{
dp[k][hs[pos]]+=tag;
return ;
}
pos++;
if(pos==limit) pos=0;
}
hs[pos]=++tot[k],state[k][tot[k]]=S,dp[k][tot[k]]=tag;
}
int main()
{
register int i,j,t,u,tmp,p,q,x,y,S,T;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%s",str+1);
for(j=1;j<=m;j++)asdasd
{
v[i][j]=str[j]=='.';
if(v[i][j]) nn=i,mm=j;
}
}
tot[0]=1,state[0][1]=0,dp[0][1]=1;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
k^=1;
memset(hs,0,sizeof(hs));
memset(state[k],0,sizeof(state[k][0])*(tot[k]+1));
memset(dp[k],0,sizeof(dp[k][0])*(tot[k]+1));
tot[k]=0;
for(t=1;t<=tot[k^1];t++)
{
S=state[k^1][t],tag=dp[k^1][t],y=j<<1,x=y-2,p=(S>>x)&3,q=(S>>y)&3,T=S^(p<<x)^(q<<y);
if(!v[i][j])
{
if(!p&&!q) upd(T);
continue;
}
if(p==0&&q==0&&v[i][j+1]&&v[i+1][j])
{
upd(T|(1<<x)|(2<<y));
continue;
}
if((p==0&&q==1)||(p==1&&q==0))
{
if(v[i+1][j]) upd(T|(1<<x));
if(v[i][j+1]) upd(T|(1<<y));
continue;
}
if((p==0&&q==2)||(p==2&&q==0))
{
if(v[i+1][j]) upd(T|(2<<x));
if(v[i][j+1]) upd(T|(2<<y));
continue;
}
if(p==2&&q==1)
{
upd(T);
continue;
}
if(p==1&&q==2&&i==nn&&j==mm)
{
ans+=tag;
continue;
}
if(p==1&&q==1)
{
for(tmp=0,u=y+2;u<=m+m&&tmp>=0;tmp+=((T>>u)&1)-((T>>(u+1))&1),u+=2);
u-=2,upd(T^(3<<u));
continue;
}
if(p==2&&q==2)
{
for(tmp=0,u=x-2;u>=0&&tmp>=0;tmp+=((T>>(u+1))&1)-((T>>u)&1),u-=2);
u+=2,upd(T^(3<<u));
continue;
}
}
}
for(t=1;t<=tot[k];t++) state[k][t]<<=2;
}
printf("%lld",ans);
return 0;
}