P5056 【模板】插头dp
题目背景
ural 1519
陈丹琦《基于连通性状态压缩的动态规划问题》中的例题
题目描述
给出(n*m)的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路。问有多少种铺法?
输入输出格式
输入格式:
第(1)行,(n,m(2le n,mle 12))
从第(2)行到第(n+1)行,每行一段字符串((m)个字符),*
表不能铺线,.
表必须铺
输出格式:
输出一个整数,表示总方案数
插头(DP)模板
几个关键字:Hash挂链,讨论,自己画图
几个细节:挂链别挂错了,好好讨论,有些地方判是为了剪枝,代码风格
几个质数:590027,299989,299987
(color{pink}{link})
Code:
#include <cstdio>
#include <cstring>
#define ll long long
const int N=3e5+10;
const int mod=299989;
int head[N],Next[N],to[N],sta[2][N],cnt[2],tot;
int n,m,ma[15][15],cur,bit[26],endx,endy;
ll dp[2][N],ans;
void Ins(int s,ll val)
{
int x=s%mod;
for(int i=head[x];i;i=Next[i])
if(sta[cur][to[i]]==s)
{
dp[cur][i]+=val;
return;
}
dp[cur][++cnt[cur]]=val;
sta[cur][cnt[cur]]=s;
to[++tot]=cnt[cur];
Next[tot]=head[x];
head[x]=tot;
}
void DP()
{
dp[cur][++cnt[cur]]=1,sta[cur][cnt[cur]]=0;
for(int i=1;i<=n;i++)
{
for(int s=1;s<=cnt[cur];s++) sta[cur][s]<<=2;
for(int j=1;j<=m;j++)
{
cur^=1;
tot=cnt[cur]=0;
memset(head,0,sizeof(head));
for(int s=1;s<=cnt[cur^1];s++)
{
int lassta=sta[cur^1][s];ll lasans=dp[cur^1][s];
int sd=(lassta>>bit[j])&3,sr=(lassta>>bit[j-1])&3;
if(!ma[i][j])
{
if(!sd&&!sr)
Ins(lassta,lasans);
}
else if(!sd&&!sr)
{
if(ma[i+1][j]&&ma[i][j+1])
Ins(lassta+(1<<bit[j-1])+(1<<bit[j]+1),lasans);
}
else if(!sd&&sr)
{
if(ma[i][j+1])//右
Ins(lassta+(sr<<bit[j])-(sr<<bit[j-1]),lasans);
if(ma[i+1][j])//下
Ins(lassta,lasans);
}
else if(sd&&!sr)
{
if(ma[i][j+1])
Ins(lassta,lasans);
if(ma[i+1][j])
Ins(lassta+(sd<<bit[j-1])-(sd<<bit[j]),lasans);
}
else if(sr==1&&sd==1)
{
int ct=1;
for(int k=j+2;k<=m+1;k++)
{
if(((lassta>>bit[k-1])&3)==1) ++ct;
if(((lassta>>bit[k-1])&3)==2) --ct;
if(!ct)
{
Ins(lassta-(sr<<bit[j-1])-(sd<<bit[j])-(1<<bit[k-1]),lasans);
break;
}
}
}
else if(sr==2&&sd==2)
{
int ct=1;
for(int k=j-1;k;k--)
{
if(((lassta>>bit[k-1])&3)==1) --ct;
if(((lassta>>bit[k-1])&3)==2) ++ct;
if(!ct)
{
Ins(lassta-(sr<<bit[j-1])-(sd<<bit[j])+(1<<bit[k-1]),lasans);
break;
}
}
}
else if(sr==2&&sd==1)
Ins(lassta-(sr<<bit[j-1])-(sd<<bit[j]),lasans);
else if(i==endx&&j==endy)
ans+=lasans;
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=25;i++) bit[i]=i<<1;
for(int i=1;i<=n;i++)
{
scanf("
");
for(int j=1;j<=m;j++)
{
char c;
scanf("%c",&c);
if(c=='.')
ma[i][j]=1,endx=i,endy=j;
}
}
DP();
printf("%lld
",ans);
return 0;
}
2018.12.20