状压DP之初尝插头DP

Posted voyage~st~Imagine

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了状压DP之初尝插头DP相关的知识,希望对你有一定的参考价值。

学了插头DP三天,终于明白了它的原理。

  然而码代码的时候仍然觉得异常恶心,分类讨论+位运算orz~~~~~学了插头DP,代码能力又上了一个台阶,感觉翻车的机会又少了~~

  先上计算哈密顿回路的代码。坑比~~两小时的码量。

感觉看别人的代码不太懂,有些东西自己推一下就出来了。

技术分享图片
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<cmath>

#define N 20
#define Mod 500009
#define L 5000000

using namespace std;

long long v[2][L];
long sum[L],bit[N+1];

long ansmod,n,m,tag,vl;

long near[N];
bool mp[N][N];

struct hash_list
{
    long long sta;
    long dp,next;
    hash_list(){}
    hash_list(long long h1,long h2,long h3)
    {
        sta=h1,dp=h2,next=h3;
    }
}phash[L];
long tot,hash[Mod];
inline void fic(long long sta,long add)
{
    long i=hash[sta%Mod],la;
    if (i==0){
        hash[sta%Mod]=++tot;
        phash[tot]=hash_list(sta,1,0);
        v[tag][++vl]=sta;
        return;
    }
    
    for (;i!=0;la=i,i=phash[i].next){
        if (phash[i].sta==sta){
            phash[i].dp=(phash[i].dp+add)%ansmod;
            return;
        }
    }
    
    phash[la].next=++tot;
    phash[tot]=hash_list(sta,1,0);
    v[tag][++vl]=sta;
}
inline long ask(long long sta)
{
    for (long i=hash[sta%Mod];i!=0;i=phash[i].next)
        if (phash[i].sta==sta)return phash[i].dp;
    return 0;
}

void dfs(long now,long ltr,long long sta)
{
    if (now>m){
        fic(sta,1);
        return;
    }
    
    if (!mp[1][now]){
        dfs(now+1,ltr,sta*4);
        return;
    }
    
    if (ltr>0)dfs(now+1,ltr-1,sta*4+2);
    if (ltr+1<=near[now]-1)dfs(now+1,ltr+1,sta*4+1);
    if (ltr<=near[now]-1)dfs(now+1,ltr+1,sta*4);
}
inline void pre()
{
    dfs(1,0,0);
}

int main()
{
    long i,j,k,endi,endj,ans;
    char str[N][N];
    scanf("%ld%ld%ld",&n,&m,&ansmod);
    for (i=1;i<=n;i++)scanf("%s",&str[i][1]);
    for (i=1,endi=endj=0;i<=n;i++){
        for (j=1;j<=m;j++)
            if (str[i][j]==.)mp[i][j]=true,endi=i,endj=j;
                else mp[i][j]=false;
        mp[i][m+1]=false;
    }
    near[m+1]=0;
    for (j=m;j>0;j--)
        if (mp[i][j])near[j]=near[j+1]+1;
            else near[j]=0;
    
    tag=0,tot=0,vl=0;
    memset(hash,0,sizeof(hash));
    pre();
    
    for (i=0;i<=m+2;i++)bit[i]=1<<2*i;
    
    ans=0;
    for (i=2;i<=n;i++){
        
        for (k=1;k<=vl;k++){
            sum[k]=v[tag][k];
            v[tag][k]=(v[tag][k]<<2)%bit[m+1];
        }
        
        for (j=1;j<=m;j++){
            if (j>1){
                for (k=1;k<=vl;k++)sum[k]=ask(v[tag][k]);
            }
            
            tag^=1;
            long pla=j-1,oldvl=vl,lplug,uplug,newsta,sta;
            vl=0,tot=0;
            memset(hash,0,sizeof(hash));
            
            if (!mp[i][j]){
                for (k=1;k<=oldvl;k++){
                    sta=v[tag^1][k];
                    lplug=sta&3*bit[pla],uplug=sta&3*bit[pla+1];
                    if (!lplug && !uplug)fic(sta,sum[k]);
                }
                continue;
            }
            
            for (k=1;k<=oldvl;k++){
                sta=v[tag^1][k],lplug=sta&3<<bit[pla],uplug=sta&3<<bit[pla+1];
                if ((lplug>>2*pla)==2&&(uplug>>2*(pla+1))){//combine
                    newsta=sta-lplug-uplug;
                    fic(newsta,sum[k]);
                } else if (i==endi&&j==endj){
                    newsta=sta-lplug-uplug;
                    if (newsta==0)ans+=sum[k];
                }
                
                if ( !(lplug&uplug) & (lplug|uplug) ){//remain
                    newsta=sta-lplug-uplug+(lplug<<2)+(uplug>>2);
                    fic(newsta,sum[k]);
                }
                
                if ( !(lplug|uplug) ){//create
                    newsta=sta+(1<<2*pla)+(2<<2*(pla+1));
                    fic(newsta,sum[k]);
                }
            }
        }
    }
    
    printf("%ld\n",ans);
    return 0;
}
View Code

 

以上是关于状压DP之初尝插头DP的主要内容,如果未能解决你的问题,请参考以下文章

POJ 2411 Mondriaan's Dream ——状压DP 插头DP

插头dp

插头DP 备忘

2331: [SCOI2011]地板 插头DP

bzoj 1814: Ural 1519 Formula 1插头dp

POJ 2411 Mondriaan's Dream -- 状压DP