标签:
插头dp
感受:
我觉得重点是理解,算法并不是直接想出怎样由一种方案变成另一种方案。而是方案本来就在那里,我们只是枚举状态统计了答案。
看看cdq的讲义什么的,一开始可能觉得状态很多,但其实灰常简单
就像lyd说的,考插头dp的题目就是在考模板2333
(学这个之前连hash_map都没写过2333
WA:
(1) 初始化矩阵,周围格子有可能是0--->转移出错
(2)统计答案最后统计的是合法的,即st==0的。。。
题目集锦:
(1)cojs1512 经过所有可经过的点的一条回路个数
因为是一条回路,依次dp每个点的状态,所以记录endx,endy只在终点更新答案,其它点的闭合回路不计算。
#include<bits/stdc++.h> using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } #define mod 13131 #define N 4500 #define ll long long struct dp_hash{ int head[mod],next[N],sz; ll f[N],st[N]; void init(){ memset(head,0,sizeof(head));sz=0; } void push(ll S,ll ins){ int now=S%mod; for(int i=head[now];i;i=next[i]) if(st[i]==S){ f[i]+=ins;return; } sz++; f[sz]=ins;st[sz]=S; next[sz]=head[now]; head[now]=sz; } }dp[2]; ll ans=0; int n,m,code[16],ch[16],a[16][16],cur,Endx,Endy; char s[15]; void Decode(ll S){ for(int i=m;i>=0;i--){ code[i]=S&7; S>>=3; } } ll Encode(){ ll S=0; memset(ch,-1,sizeof(ch));int cnt=0; ch[0]=0; for(int i=0;i<=m;i++){ if(ch[code[i]]==-1)ch[code[i]]=++cnt; code[i]=ch[code[i]]; S<<=3;S|=code[i]; } return S; } void Shift(){ for(int i=m;i>0;i--)code[i]=code[i-1]; code[0]=0; } void DP(int x,int y,int pre,bool type){ if(!type){ for(int k=1;k<=dp[pre].sz;k++){ Decode(dp[pre].st[k]); if(y==m)Shift(); dp[pre^1].push(Encode(),dp[pre].f[k]); } return; } for(int k=1;k<=dp[pre].sz;k++){ Decode(dp[pre].st[k]); int Left=code[y-1],Up=code[y]; if(Left&&Up){ if(Left==Up){ if(Endx==x&&Endy==y) ans+=dp[cur].f[k]; } else{ code[y]=code[y-1]=0; for(int i=0;i<=m;i++) if(code[i]==Up)code[i]=Left; if(y==m)Shift(); dp[pre^1].push(Encode(),dp[pre].f[k]); } } else if(Left==0&&Up==0){ if(a[x][y+1]&&a[x+1][y]){ code[y-1]=code[y]=15; dp[pre^1].push(Encode(),dp[pre].f[k]); } } else{ int tmp=Left==0?Up:Left; if(a[x][y+1]){ code[y-1]=0;code[y]=tmp; if(y==m)Shift(); dp[pre^1].push(Encode(),dp[pre].f[k]); } if(a[x+1][y]){ code[y-1]=tmp;code[y]=0; if(y==m)Shift(); dp[pre^1].push(Encode(),dp[pre].f[k]); } } } } int main(){ freopen("formula1.in","r",stdin); freopen("formula1.out","w",stdout); n=read();m=read(); for(int i=1;i<=n;i++){ scanf("%s",s+1); for(int j=1;j<=m;j++) if(s[j]!=‘*‘){ a[i][j]=1; Endx=i;Endy=j; } } if(Endx==0){ puts("0");return 0; } cur=0; dp[cur].init(); dp[cur].push(0,1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ dp[cur^1].init(); DP(i,j,cur,a[i][j]); cur^=1; } printf("%lld\n",ans); return 0; }
(2) hdu1693 Eat The Trees
经过所有非障碍点的回路个数(不限条数)。
和上一道题的区别就是非终点的回路也要更新其它状态。
#include<bits/stdc++.h> using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } #define N 1000000 #define mod 13131 #define ll long long struct dphash{ int head[N],next[N],sz; ll st[N],f[N]; void init(){ memset(head,0,sizeof(head));sz=0; } void push(ll S,ll ins){ int now=S%mod; for(int i=head[now];i;i=next[i]) if(st[i]==S){ f[i]+=ins;return; } sz++; st[sz]=S;f[sz]=ins; next[sz]=head[now];head[now]=sz; } }dp[2]; int n,m,T,cur,pw[16],a[16][16],code[16]; ll ans; ll Encode(){ ll S=0; memset(pw,-1,sizeof(pw)); pw[0]=0;int cnt=0; for(int i=0;i<=m;i++){ if(pw[code[i]]==-1)pw[code[i]]=++cnt; code[i]=pw[code[i]]; S<<=3;S|=code[i]; } return S; } void Decode(ll S){ for(int i=m;i>=0;i--){ code[i]=S&7; S>>=3; } } void Shift(){ for(int i=m;i;i--)code[i]=code[i-1]; code[0]=0; } void DP(int x,int y,int pre,bool type){ if(!type){ for(int i=1;i<=dp[pre].sz;i++){ Decode(dp[pre].st[i]); // cout<<"code "<<code[y]<<‘ ‘<<code[y-1]<<endl; code[y]=code[y-1]=0; if(y==m)Shift(); dp[pre^1].push(Encode(),dp[pre].f[i]); } return; } for(int i=1;i<=dp[pre].sz;i++){ Decode(dp[pre].st[i]); int Left=code[y-1],Up=code[y]; if(Left&&Up){ code[y]=code[y-1]=0; for(int j=0;j<=m;j++)if(code[j]==Up)code[j]=Left; if(y==m)Shift(); dp[pre^1].push(Encode(),dp[pre].f[i]); } else if(Left==0&&Up==0){ if(a[x][y+1]&&a[x+1][y]){ code[y-1]=code[y]=15; dp[pre^1].push(Encode(),dp[pre].f[i]); } } else{ int tmp=Left==0?Up:Left; if(a[x][y+1]){ code[y]=tmp;code[y-1]=0; dp[pre^1].push(Encode(),dp[pre].f[i]); } if(a[x+1][y]){ code[y-1]=tmp;code[y]=0; if(y==m)Shift(); dp[pre^1].push(Encode(),dp[pre].f[i]); } } } } int main(){ // freopen("1693.in","r",stdin); // freopen("1693.out","w",stdout); T=read(); for(int k=1;k<=T;k++){ memset(a,0,sizeof(a)); n=read();m=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)a[i][j]=read(); cur=0; dp[cur].init(); dp[cur].push(0,1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ dp[cur^1].init(); DP(i,j,cur,a[i][j]); cur^=1; } ans=0; for(int i=dp[cur].head[0];i;i=dp[cur].next[i])if(dp[cur].st[i]==0)ans+=dp[cur].f[i]; printf("Case %d: There are %I64d ways to eat the trees.\n",k,ans); } return 0; }
(3)[国家集训队2011]画圈圈
根据射线法,判断一个点左边的下插头奇偶性判断是否在回路内。
#include<bits/stdc++.h> using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } #define ll long long #define N 1000000 #define mod 13131 #define MOD 123456791 struct dp_hash{ int head[mod],next[N],sz; ll f[N],st[N]; void init(){ memset(head,0,sizeof(head));sz=0; } void push(ll S,ll ins){ ins%=MOD;int now=S%mod; for(int i=head[now];i;i=next[i]) if(st[i]==S){ (f[i]+=ins)%=MOD;return; } sz++;next[sz]=head[now];head[now]=sz; st[sz]=S;f[sz]=ins; } }dp[2]; int n,m,cur,pw[16],a[25][16],code[16]; ll ans; char s[16]; void Decode(ll S){ for(int i=m;i>=0;i--){ code[i]=S&7; S>>=3; } } ll Encode(){ ll S=0; memset(pw,-1,sizeof(pw)); pw[0]=0;int cnt=0; for(int i=0;i<=m;i++){ if(pw[code[i]]==-1)pw[code[i]]=++cnt; code[i]=pw[code[i]]; S<<=3;S|=code[i]; } return S; } void Shift(){ for(int i=m;i;i--)code[i]=code[i-1]; code[0]=0; } void DP(int x,int y,int pre,int type){ if(type){ for(int i=1;i<=dp[pre].sz;i++){ Decode(dp[pre].st[i]);int t=0; for(int j=0;j<y-1;j++)if(code[j]!=0)t++; if((t%2==1&&type==1)||(t%2==0&&type==2)){ if(y==m)Shift(); dp[pre^1].push(Encode(),dp[pre].f[i]); } } return; } for(int i=1;i<=dp[pre].sz;i++){ Decode(dp[pre].st[i]); int Left=code[y-1],Up=code[y]; if(Left&&Up){ code[y]=code[y-1]=0; for(int j=0;j<=m;j++)if(code[j]==Up)code[j]=Left; if(y==m)Shift(); dp[pre^1].push(Encode(),dp[pre].f[i]); } else if(Left==0&&Up==0){ if(a[x][y+1]==0&&a[x+1][y]==0){ code[y-1]=code[y]=15; dp[pre^1].push(Encode(),dp[pre].f[i]); } } else{ int tmp=Left==0?Up:Left; if(a[x][y+1]==0){ code[y]=tmp;code[y-1]=0; dp[pre^1].push(Encode(),dp[pre].f[i]); } if(a[x+1][y]==0){ code[y-1]=tmp;code[y]=0; if(y==m)Shift(); dp[pre^1].push(Encode(),dp[pre].f[i]); } } } } int main(){ freopen("nt2011_circle.in","r",stdin); freopen("nt2011_circle.out","w",stdout); n=read();m=read(); memset(a,-1,sizeof(a)); for(int i=1;i<=n;i++){ scanf("%s",s+1); for(int j=1;j<=m;j++) if(s[j]==‘.‘)a[i][j]=0; else if(s[j]==‘*‘)a[i][j]=1; else a[i][j]=2; } cur=0; dp[cur].init(); dp[cur].push(0,1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ dp[cur^1].init(); DP(i,j,cur,a[i][j]); cur^=1; } for(int i=dp[cur].head[0];i;i=dp[cur].next[i])if(dp[cur].st[i]==0){ans=dp[cur].f[i];break;} printf("%lld\n",ans); }
(4)BZOJ1187&&BZOJ3753
都是把记录方案个数的变量改为记录当前状态得到的权值
还没写QAQ
标签:
原文地址:http://www.cnblogs.com/wjyi/p/5654500.html