插头dp模板

P5056 【模板】插头dp

题目背景

ural 1519

陈丹琦《基于连通性状态压缩的动态规划问题》中的例题

题目描述

给出\(n*m\)的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路。问有多少种铺法?

输入输出格式

输入格式:

\(1\)行,\(n,m(2\le n,m\le 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("\n");
        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\n",ans);
    return 0;
}

2018.12.20

posted @ 2018-12-20 17:18  露迭月  阅读(314)  评论(0编辑  收藏  举报