题目描述
题解
第一次写插头dp
求哈密顿回路:https://blog.csdn.net/litble/article/details/79369147,本质是维护轮廓线+左右括号序列
本题只需要维护下/右插头即可,状态数是C(m,3)级别的,压一压即可
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
//#define file
using namespace std;
ll f[4527][4][2],g[4527][4][2],ans;
int num[31][31][31],b[4527][3],n,m,i,j,k,l,tot,I[3];
bool bz[31][31];
char ch;
void swap(int &x,int &y) {int z=x;x=y;y=z;}
int main()
{
#ifdef file
freopen("loj2099.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
fo(i,1,n)
{
fo(j,1,m)
{
ch=getchar();
while (ch!='.' && ch!='#') ch=getchar();
bz[i][j]=ch=='#';
}
}
tot=1;num[0][0][0]=1;b[1][0]=0,b[1][1]=0,b[1][2]=0;
fo(i,1,m)
{
num[i][0][0]=++tot;
b[tot][0]=i,b[tot][1]=0,b[tot][2]=0;
fo(j,1,i-1)
{
num[i][j][0]=++tot;
b[tot][0]=i,b[tot][1]=j,b[tot][2]=0;
fo(k,1,j-1)
num[i][j][k]=++tot,b[tot][0]=i,b[tot][1]=j,b[tot][2]=k;
}
}
f[1][0][0]=1;
fo(i,1,n)
{
fo(j,0,m-1)
{
memset(g,0,sizeof(g));
fo(k,1,tot)
{
fo(l,0,3)
{
if (!bz[i][j+1])
{
I[0]=b[k][0],I[1]=b[k][1],I[2]=b[k][2];
if (I[0]==j+1) g[num[I[1]][I[2]][0]][l][1]+=f[k][l][0];
else
if (I[1]==j+1) g[num[I[0]][I[2]][0]][l][1]+=f[k][l][0];
else
if (I[2]==j+1) g[num[I[0]][I[1]][0]][l][1]+=f[k][l][0];
else
if (l<3)
{
I[2]=j+1;
if (I[2]>I[1]) swap(I[1],I[2]);
if (I[1]>I[0]) swap(I[0],I[1]);
g[num[I[0]][I[1]][I[2]]][l+1][0]+=f[k][l][0];
}
if (b[k][0]!=j+1 && b[k][1]!=j+1 && b[k][2]!=j+1)
{
g[k][l][0]+=f[k][l][1];
g[k][l][1]+=f[k][l][1];
}
}
if (!bz[i][j+1] || (b[k][0]!=j+1 && b[k][1]!=j+1 && b[k][2]!=j+1)) g[k][l][0]+=f[k][l][0];
}
}
memcpy(f,g,sizeof(f));
}
if (i<n)
{
fo(k,1,tot)
{
fo(l,0,3)
f[k][l][1]=0;
}
}
}
printf("%lld
",f[1][3][0]);
fclose(stdin);
fclose(stdout);
return 0;
}