DPDP插座DP

1 篇文章 0 订阅

sjy插() 头DP是一种解决平面内回路问题的DP,一般用状压解决。不难思考,代码量巨多,分类讨论烦死人。

代码(具体看注释)

很详细了,看不懂的yy一下

#include<cstdio>
#include<iostream>
#include<cstring>
#define MAXN 300010
using namespace std;
int n,m;
int has=299989;
int lstx,lsty;
long long bin[15];
long long tot[2];//状态总数 
long long js[2][MAXN];//具体状态的方案数 
long long a[2][MAXN];//存储的具体状态是什么 
long long mapp[15][15];//地图 
long long ans; //答案 
int fst[300005];
int nxt[300005]; //哈希表 
int las,now;//滚动数组 
//qtmdsjyczdp 
void add(int zt,long long num)
{
    // hash table 
    int x=zt%has+1;
    for(int i=fst[x];i;i=nxt[i])
    {
        if(a[now][i]==zt)
        {
            js[now][i]+=num;return ;
        }
    }
    tot[now]++;
    nxt[tot[now]]=fst[x];
    fst[x]=tot[now];
    a[now][tot[now]]=zt;
    js[now][tot[now]]=num;
}
void DP()
{
	//预处理,0行的状态只有一个,为 0 
    tot[now]=1;
    js[now][1]=1;
    a[now][1]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=tot[now];j++)
        {
            a[now][j]<<=2;//换行时左移一位 
        }
        for(int j=1;j<=m;j++)
        {
            las=now;
            now^=1;//滚动 
            memset(fst,0,sizeof(fst));//初始化表头 
            tot[now]=0;
            for(int k=1;k<=tot[las];k++)
            {
                int zt=a[las][k];
                int b1=(zt>>(j*2-2))&3;
                int b2=(zt>>(j*2))&3;//提取插头状态 b1左插头 b2上插头  
                long long num=js[las][k];//状态数 
                if(!mapp[i][j])//不允许走 
                {
 
                    if(!b1&&!b2)add(zt,num);//合法 
                     
                }
                else if(!b1&&!b2)// 0 0
                {
                     
                    if(mapp[i][j+1]&&mapp[i+1][j])//合法 
                    {
                     
                    add(zt+bin[j-1]+2*bin[j],num); //j-1改为1 j改为2 
                    }
                }
                else if(!b1&&b2)//b1==0 
                {
                    if(mapp[i][j+1])add(zt,num);//左连下 状态不变 
                    if(mapp[i+1][j])add(zt-bin[j]*b2+bin[j-1]*b2,num);//左连右 j j-1互换 
                }
                else if(b1&&!b2)//同上 
                {
                    if(mapp[i][j+1])add(zt+bin[j]*b1-bin[j-1]*b1,num);
                    if(mapp[i+1][j])add(zt,num);
                }
                else if(b1==1&&b2==1)//同左插头 强行掰过来(滑稽) 
                {
                     
                    int kl=1;
                    for(int kk=j+1;kk<=m;kk++)
                    {
                        if(((zt>>(kk*2))&3)==1)kl++;
                        if(((zt>>(kk*2))&3)==2)kl--;
                        if(!kl)
                        {
                            add(zt-bin[j]-bin[j-1]-bin[kk],num);
                            break;
                        }
                    }
                }
                else if(b1==2&&b2==2)//同上 
                {
                    int kl=1;
                    for(int kk=j-2;kk>=0;kk--)
                    {
                    if(((zt>>(kk*2))&3)==1)kl--;
                    if(((zt>>(kk*2))&3)==2)kl++;
                    if(!kl)
                    {
                        add(zt-2*bin[j]-2*bin[j-1]+bin[kk],num);
                        break;
                    }
                    }
                }
                else if(b1==2&&b2==1)add(zt-2*bin[j-1]-bin[j],num);//直接消消乐 
                else if(i==lstx&&j==lsty)ans+=num;//统计答案 
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j) {
        char ch=getchar();
        while(ch!='*'&&ch!='.') ch=getchar();
        if(ch=='.') mapp[i][j]=1,lstx=i,lsty=j;// lst表示最后可走的点 
    }
    bin[0]=1;
    for(int i=1;i<=12;i++)//预处理4进制 
    bin[i]=bin[i-1]<<2; 
    DP();
    printf("%lld",ans);
    return 0;
}

再给一份没有注释的(你懂的)

#include<cstdio>
#include<iostream>
#include<cstring>
#define MAXN 300010
using namespace std;
int n,m;
int has=299989;
int lstx,lsty;
long long bin[15];
long long tot[2];
long long js[2][MAXN];
long long a[2][MAXN];
long long mapp[15][15];
long long ans;
int fst[300005];
int nxt[300005];
int las,now;
void add(int zt,long long num)
{
    //cout<<zt<<endl;
    int x=zt%has+1;
    for(int i=fst[x];i;i=nxt[i])
    {
        if(a[now][i]==zt)
        {
            js[now][i]+=num;return ;
        }
    }
    tot[now]++;
    nxt[tot[now]]=fst[x];
    fst[x]=tot[now];
    a[now][tot[now]]=zt;
    js[now][tot[now]]=num;
}
void DP()
{
    tot[now]=1;
    js[now][1]=1;
    a[now][1]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=tot[now];j++)
        {
            a[now][j]<<=2;
        }
        for(int j=1;j<=m;j++)
        {
            las=now;
            now^=1;
            memset(fst,0,sizeof(fst));
            tot[now]=0;
            for(int k=1;k<=tot[las];k++)
            {
                int zt=a[las][k];
                int b1=(zt>>(j*2-2))&3;
                int b2=(zt>>(j*2))&3;
                long long num=js[las][k];
                if(!mapp[i][j])
                {
 
                    if(!b1&&!b2)add(zt,num);
                     
                }
                else if(!b1&&!b2)
                {
                     
                    if(mapp[i][j+1]&&mapp[i+1][j])
                    {
                     
                    add(zt+bin[j-1]+2*bin[j],num);  
                    }
                }
                else if(!b1&&b2)
                {
                    //cout<<"c";
                    if(mapp[i][j+1])add(zt,num);
                    if(mapp[i+1][j])add(zt-bin[j]*b2+bin[j-1]*b2,num);
                }
                else if(b1&&!b2)
                {
                    if(mapp[i][j+1])add(zt+bin[j]*b1-bin[j-1]*b1,num);
                    if(mapp[i+1][j])add(zt,num);
                }
                else if(b1==1&&b2==1)
                {
                     
                    int kl=1;
                    for(int kk=j+1;kk<=m;kk++)
                    {
                        if(((zt>>(kk*2))&3)==1)kl++;
                        if(((zt>>(kk*2))&3)==2)kl--;
                        if(!kl)
                        {
                            add(zt-bin[j]-bin[j-1]-bin[kk],num);
                            break;
                        }
                    }
                }
                else if(b1==2&&b2==2)
                {
                    int kl=1;
                    for(int kk=j-2;kk>=0;kk--)
                    {
                    if(((zt>>(kk*2))&3)==1)kl--;
                    if(((zt>>(kk*2))&3)==2)kl++;
                    if(!kl)
                    {
                        add(zt-2*bin[j]-2*bin[j-1]+bin[kk],num);
                        break;
                    }
                    }
                }
                else if(b1==2&&b2==1)add(zt-2*bin[j-1]-bin[j],num);
                else if(i==lstx&&j==lsty)ans+=num;
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j) {
        char ch=getchar();
        while(ch!='*'&&ch!='.') ch=getchar();
        if(ch=='.') mapp[i][j]=1,lstx=i,lsty=j;
    }
    bin[0]=1;
    for(int i=1;i<=12;i++)
    bin[i]=bin[i-1]<<2;
    DP();
    printf("%lld",ans);
    return 0;
}

 odk~~

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值