LG P5056 【模板】插头dp

Descriprion

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

Solution

使用括号表示法记录状态,记1为 '(' ,2为 ')' ,0为无插头,分8种情况讨论:

  • 1:当前格子有障碍,此时必须下插头和右插头为0,转移后状态不变
  • 2:当前格子下插头和右插头为0,转移后右插头为1,下插头为2
  • 3:当前格子有右插头,无下插头,转移后右插头位置不变或向右移动一位
  • 4:当前格子有下插头,无右插头,转移后下插头位置不变或向左移动一位
  • 5:当前格子下插头和右插头为1,转移后从当前格子向右首个不匹配的2变为1
  • 6:当前格子下插头和右插头为2,转移后从当前格子向左首个不匹配的1变为2
  • 7:当前格子右插头为2,左插头为1,转移后删除两插头
  • 8:当前格子右插头为1,左插头为2,此时必须为最后一个可访问格子,更新总答案

优化:使用链表存储状态为模数同余系的状态;滚动数组

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int n,m,map[15][15],endx,endy,bits[15],pre=1,cur,tots[2],state[2][600000],head[600000],tot;
const int mod=590027;
long long ans,dp[2][600000];
struct Edge
{
    int to,nxt;
}edge[600000];
inline int read()
{
    int f=1,w=0;
    char ch=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        w=(w<<1)+(w<<3)+ch-'0';
        ch=getchar();
    }
    return f*w;
}
void insert(int sta,long long val)
{
    int key=sta%mod;
    for(int i=head[key];i;i=edge[i].nxt)
    {
        if(state[cur][edge[i].to]==sta)
        {
            dp[cur][edge[i].to]+=val;
            return;
        }
    }
    tots[cur]++;
    state[cur][tots[cur]]=sta;
    dp[cur][tots[cur]]=val;
    edge[++tot]=(Edge){tots[cur],head[key]};
    head[key]=tot;
}
void DP()
{
    tots[cur]=1;
    state[cur][1]=0;
    dp[cur][1]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=tots[cur];j++)
        {
            state[cur][j]<<=2;
        }
        for(int j=1;j<=m;j++)
        {
            tot=0;
            memset(head,0,sizeof(head));
            swap(cur,pre);
            tots[cur]=0;
            int nowsta=0,d=0,r=0;
            long long nowans=0;
            for(int k=1;k<=tots[pre];k++)
            {
                nowsta=state[pre][k];
                nowans=dp[pre][k];
                d=(nowsta>>bits[j])%4;
                r=(nowsta>>bits[j-1])%4;
                if(!map[i][j])
                {
                    if(!d&&!r)
                    {
                        insert(nowsta,nowans);
                    }
                }
                else if(!d&&!r)
                {
                    if(map[i+1][j]&&map[i][j+1])
                    {
                        insert(nowsta+(1<<bits[j-1])+2*(1<<bits[j]),nowans);
                    }
                }
                else if(!d&&r)
                {
                    if(map[i+1][j])
                    {
                        insert(nowsta,nowans);
                    }
                    if(map[i][j+1])
                    {
                        insert(nowsta-r*(1<<bits[j-1])+r*(1<<bits[j]),nowans);
                    }
                }
                else if(!r&&d)
                {
                    if(map[i][j+1])
                    {
                        insert(nowsta,nowans);
                    }
                    if(map[i+1][j])
                    {
                        insert(nowsta-d*(1<<bits[j])+d*(1<<bits[j-1]),nowans);
                    }
                }
                else if(r==1&&d==1)
                {
                    int cnt=1;
                    for(int l=j+1;l<=m;l++)
                    {
                        if((nowsta>>bits[l])%4==1)
                        {
                            cnt++;
                        }
                        else if((nowsta>>bits[l])%4==2)
                        {
                            cnt--;
                        }
                        if(!cnt)
                        {
                            insert(nowsta-(1<<bits[j-1])-(1<<bits[j])-(1<<bits[l]),nowans);
                            break;
                        }
                    }
                }
                else if(r==2&&d==2)
                {
                    int cnt=1;
                    for(int l=j-2;l>=0;l--)
                    {
                        if((nowsta>>bits[l])%4==1)
                        {
                            cnt--;
                        }
                        else if((nowsta>>bits[l])%4==2)
                        {
                            cnt++;
                        }
                        if(!cnt)
                        {
                            insert(nowsta-2*(1<<bits[j-1])-2*(1<<bits[j])+(1<<bits[l]),nowans);
                            break;
                        }
                    }
                }
                else if(r==2&&d==1)
                {
                    insert(nowsta-2*(1<<bits[j-1])-(1<<bits[j]),nowans);
                }
                else
                {
                    if(i==endx&&j==endy)
                    {
                        ans+=nowans;
                    }
                }
            }
        }
    }
}
int main()
{
    n=read();
    m=read();
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            char ch=0;
            while(ch!='.'&&ch!='*')
            {
                ch=getchar();
            }
            if(ch=='.')
            {
                map[i][j]=1;
                endx=i;
                endy=j;
            }
        }
    }
    for(int i=1;i<=14;i++)
    {
        bits[i]=i<<1;
    }
    DP();
    printf("%lld\n",ans);
    return 0;
}
【模板】插头dp

 

posted @ 2020-07-29 16:45  QDK_Storm  阅读(196)  评论(1编辑  收藏  举报