洛谷P3190 [HNOI2007]神奇游乐园(插头dp)

传送门

大概是算第一道自己做出来的插头dp?

(虽然都是照着抄板子的)

(虽然有个地方死活没调出来最后只能看题解才发现自己错在哪里的)

我就当你们都会插头dp了……

因为必须得是一条路径,所以扫描线上的插头得两两对应,要用括号序列

然后分情况讨论一下,记$p1$为当前关键格左边的插头,$p2$为当前关键格上面的插头

$0$表示无插头,$1$表示左括号,$2$表示右括号

1.$p1==0$且$p2==0$

那么很明显我们可以把下方插头设为$1$右方插头设为$2$,就形成一个新的连通块了

然后注意不设任何插头的状态也要转移(我就是在这里坑了一个晚上)

2.$p1!=0$且$p2==0$

那么我们有两种走法,一是直走,那么右插头的值就是原插头的值,一是拐弯,那么下面的插头的值就是左插头的值

3.$p1==0$且$p2!=0$

同上,不多说了

4.$p1==1$且$p2==1$

就是两个左括号撞到一起了,那么把$p2$对应的右括号改成左括号

5.$p1==1$且$p2==2$

这种情况就说明一条路径已经结束了,那么此时如果轮廓线上没有其他任何插头就可以更新答案了

6.$p1==2$且$p2==1$

两条路径在这里汇合,直接合并

7.$p1==2$且$p2==2$

两个右括号撞到一起了,那么把$p1$对应的左括号改成右括号

然后……剩下的看代码好了(似乎我的插头dp写法和很多人不一样诶……)

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #define ll long long
 6 #define inf 0x3f3f3f3f3f3f3f3f
 7 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
 8 const int mod=200097;
 9 int n,m,c[105][105];ll ans=-0x3f3f3f3f3f3f3f3f;
10 struct Ha{
11     int key[mod],sz,Hash[mod];ll val[mod];
12     inline void init(){
13         memset(val,0xef,sizeof(val)),memset(key,-1,sizeof(key));
14         sz=0,memset(Hash,0,sizeof(Hash));
15     }
16     inline void newhash(int id,int state){Hash[id]=++sz,key[sz]=state,val[sz]=-inf;}
17     ll &operator [](const int state){
18         for(int i=state%mod;;i=(i+1==mod)?0:i+1){
19             if(!Hash[i]) newhash(i,state);
20             if(key[Hash[i]]==state) return val[Hash[i]];
21         }
22     }
23 }f[2];
24 inline int find(int state,int id){return (state>>((id-1)<<1))&3;}
25 inline void set(int &state,int pos,int val){
26     pos=(pos-1)<<1,state|=3<<pos,state^=3<<pos,state|=val<<pos;
27 }
28 int link(int state,int pos){
29     int cnt=0,del=(find(state,pos)==1)?1:-1;
30     for(int i=pos;i&&i<=m+1;i+=del){
31         int plug=find(state,i);
32         if(plug==1) ++cnt;
33         else if(plug==2) --cnt;
34         if(!cnt) return i;
35     }
36     return -1;
37 }
38 void solve(int x,int y){
39     int now=((x-1)*m+y)&1,last=now^1,tot=f[last].sz;
40     f[now].init();
41     for(int i=1;i<=tot;++i){
42         int state=f[last].key[i];ll val=f[last].val[i];
43         int plug1=find(state,y),plug2=find(state,y+1);
44         if(!plug1&&!plug2){
45             cmax(f[now][state],val);
46             if(x!=n&&y!=m) set(state,y,1),set(state,y+1,2),cmax(f[now][state],val+c[x][y]);
47         }
48         else if(plug1&&!plug2){
49             if(x!=n) cmax(f[now][state],val+c[x][y]);
50             if(y!=m) set(state,y,0),set(state,y+1,plug1),cmax(f[now][state],val+c[x][y]);
51         }
52         else if(!plug1&&plug2){
53             if(y!=m) cmax(f[now][state],val+c[x][y]);
54             if(x!=n) set(state,y,plug2),set(state,y+1,0),cmax(f[now][state],val+c[x][y]);
55         }
56         else if(plug1==1&&plug2==1)
57         set(state,link(state,y+1),1),set(state,y,0),set(state,y+1,0),cmax(f[now][state],val+c[x][y]);
58         else if(plug1==1&&plug2==2){
59             set(state,y,0),set(state,y+1,0);
60             if(!state) cmax(ans,val+c[x][y]);
61         }
62         else if(plug1==2&&plug2==1) set(state,y,0),set(state,y+1,0),cmax(f[now][state],val+c[x][y]);
63         else if(plug1==2&&plug2==2)
64         set(state,link(state,y),2),set(state,y,0),set(state,y+1,0),cmax(f[now][state],val+c[x][y]);
65     }
66 }
67 int main(){
68 //    freopen("testdata.in","r",stdin);
69     scanf("%d%d",&n,&m);
70     for(int i=1;i<=n;++i)
71     for(int j=1;j<=m;++j)
72     scanf("%d",&c[i][j]);
73     f[0].init(),f[0][0]=0;
74     for(int i=1;i<=n;++i){
75         for(int j=1;j<=m;++j) solve(i,j);
76         if(i!=n){
77             int now=(i*m)&1,tot=f[now].sz;
78             for(int j=1;j<=tot;++j)
79             f[now].key[j]<<=2;
80         }
81     }
82     printf("%lld
",ans);
83     return 0;
84 }
原文地址:https://www.cnblogs.com/bztMinamoto/p/9664814.html