状压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; }
以上是关于状压DP之初尝插头DP的主要内容,如果未能解决你的问题,请参考以下文章
POJ 2411 Mondriaan's Dream ——状压DP 插头DP