[HNOI2007] 神奇游乐园 [插头dp]

Posted Orion545

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HNOI2007] 神奇游乐园 [插头dp]相关的知识,希望对你有一定的参考价值。

题面:

传送门

给定一个四联通棋盘图,每个格子有权值,求一条总权值最大的回路

思路:

插头dp基础教程

棋盘?

回路?

n,m<=10?

当然是插头dp啦~\\(≧▽≦)/~

 

然后发现这道题并不是哈密顿回路了......需要考虑一下终止条件的不同,对比URAL1519

诚然,回路问题中依然可以用括号表示法来压缩状态,但是此时形成回路、统计答案的就不仅仅在最后一个非障碍格子才可以,而是任何时候,只要状态中只剩下一对左右插头满足条件(看不懂这里的可以去上面那道题看看)

同时请注意,这道题统计的是最值、不是和值

同时请注意,这题可能会爆longlong......我丧病地开了__int128,避免了高精度的地狱

 

Code:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define ll long long
  6 #define hash deep_dark_fantasy
  7 #define inf 1e9
  8 using namespace std;
  9 inline int read(){
 10     int re=0,flag=1;char ch=getchar();
 11     while(ch>\'9\'||ch<\'0\'){
 12         if(ch==\'-\') flag=-1;
 13         ch=getchar();
 14     }
 15     while(ch>=\'0\'&&ch<=\'9\') re=(re<<1)+(re<<3)+ch-\'0\',ch=getchar();
 16     return re*flag;
 17 }
 18 int n,m,x[150][150],cur,pre,ex,ey;
 19 int st[2][300010];ll ans[2][300010],re;
 20 int tot[2],bit[20],state[300010],st_tot,hash=300000;
 21 struct edge{
 22     int to,next;
 23 }a[300010];
 24 void insert(int sta,ll val){
 25     int p=sta%hash,i;
 26     for(i=state[p];i;i=a[i].next){
 27         if(st[cur][a[i].to]==sta){
 28             ans[cur][a[i].to]=max(ans[cur][a[i].to],val);return;
 29         }
 30     }
 31     tot[cur]++;
 32     a[++st_tot].to=tot[cur];
 33     a[st_tot].next=state[p];
 34     state[p]=st_tot;st[cur][tot[cur]]=sta;ans[cur][tot[cur]]=val;
 35 }
 36 void dp(){
 37     int i,j,k,l,now,down,right;ll val;re=-inf;
 38     cur=0;tot[cur]=1;ans[cur][1]=0;st[cur][1]=0;
 39     for(i=1;i<=n;i++){
 40         for(j=1;j<=tot[cur];j++) st[cur][j]<<=2;
 41         for(j=1;j<=m;j++){
 42             pre=cur;cur^=1;tot[cur]=0;st_tot=0;memset(state,0,sizeof(state));
 43             for(k=1;k<=tot[pre];k++){
 44                 now=st[pre][k];val=ans[pre][k];
 45                 right=(now>>bit[j-1])%4;down=(now>>bit[j])%4;
 46                 if(!down&&!right){
 47                     insert(now,val);
 48                     if(j!=m) 
 49                         insert(now+(1<<bit[j-1])+((1<<bit[j])<<1),val+x[i][j]);
 50                 }
 51                 if(down&&!right){
 52                     insert(now-down*(1<<bit[j])+down*(1<<bit[j-1]),val+x[i][j]);
 53                     if(j!=m)insert(now,val+x[i][j]);
 54                 }
 55                 if(right&&!down){
 56                     insert(now,val+x[i][j]);
 57                     if(j!=m) 
 58                         insert(now+right*(1<<bit[j])-right*(1<<bit[j-1]),val+x[i][j]);
 59                 }
 60                 if(right==1&&down==1){
 61                     int cnt=1;
 62                     for(l=j+1;l<=m;l++){
 63                         if((now>>bit[l])%4==1) cnt++;
 64                         if((now>>bit[l])%4==2) cnt--;
 65                         if(!cnt){
 66                             insert(now-(1<<bit[l])-(1<<bit[j])-(1<<bit[j-1]),val+x[i][j]);
 67                             break;
 68                         }
 69                     }
 70                 }
 71                 if(right==2&&down==2){
 72                     int cnt=1;
 73                     for(l=j-2;l>=0;l--){
 74                         if((now>>bit[l])%4==1) cnt--;
 75                         if((now>>bit[l])%4==2) cnt++;
 76                         if(!cnt){
 77                             insert(now+(1<<bit[l])-((1<<bit[j])<<1)-((1<<bit[j-1])<<1),val+x[i][j]);
 78                             break;
 79                         }
 80                     }
 81                 }
 82                 if(right==2&&down==1){
 83                     insert(now-((1<<bit[j-1])<<1)-(1<<bit[j]),val+x[i][j]);
 84                 }
 85                 if(right==1&&down==2){
 86                     if((now==(1<<bit[j-1])+((1<<bit[j])<<1))&&(val+x[i][j]>re)){
 87                         re=val+x[i][j];
 88                     }
 89                 }
 90             }
 91         }
 92     }
 93 }
 94 int main(){
 95     int i,j;
 96     n=read();m=read();
 97     for(i=1;i<=10;i++) bit[i]=(i<<1);
 98     for(i=1;i<=n;i++) for(j=1;j<=m;j++) x[i][j]=read();
 99     dp();
100     printf("%lld",re);
101 }

 

以上是关于[HNOI2007] 神奇游乐园 [插头dp]的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1187[HNOI2007]神奇游乐园 插头dp

插头DPBZOJ1187- [HNOI2007]神奇游乐园

[HNOI2007]神奇游乐园

插头dp题表(已完成)

Bzoj1187神奇游乐园(插头DP)

BZOJ1187:[HNOI2007]神奇游乐园——题解