传送门

大概是算第一道自己做出来的插头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写法和很多人不一样诶……)

 //minamoto
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3f
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,:;}
const int mod=;
int n,m,c[][];ll ans=-0x3f3f3f3f3f3f3f3f;
struct Ha{
int key[mod],sz,Hash[mod];ll val[mod];
inline void init(){
memset(val,0xef,sizeof(val)),memset(key,-,sizeof(key));
sz=,memset(Hash,,sizeof(Hash));
}
inline void newhash(int id,int state){Hash[id]=++sz,key[sz]=state,val[sz]=-inf;}
ll &operator [](const int state){
for(int i=state%mod;;i=(i+==mod)?:i+){
if(!Hash[i]) newhash(i,state);
if(key[Hash[i]]==state) return val[Hash[i]];
}
}
}f[];
inline int find(int state,int id){return (state>>((id-)<<))&;}
inline void set(int &state,int pos,int val){
pos=(pos-)<<,state|=<<pos,state^=<<pos,state|=val<<pos;
}
int link(int state,int pos){
int cnt=,del=(find(state,pos)==)?:-;
for(int i=pos;i&&i<=m+;i+=del){
int plug=find(state,i);
if(plug==) ++cnt;
else if(plug==) --cnt;
if(!cnt) return i;
}
return -;
}
void solve(int x,int y){
int now=((x-)*m+y)&,last=now^,tot=f[last].sz;
f[now].init();
for(int i=;i<=tot;++i){
int state=f[last].key[i];ll val=f[last].val[i];
int plug1=find(state,y),plug2=find(state,y+);
if(!plug1&&!plug2){
cmax(f[now][state],val);
if(x!=n&&y!=m) set(state,y,),set(state,y+,),cmax(f[now][state],val+c[x][y]);
}
else if(plug1&&!plug2){
if(x!=n) cmax(f[now][state],val+c[x][y]);
if(y!=m) set(state,y,),set(state,y+,plug1),cmax(f[now][state],val+c[x][y]);
}
else if(!plug1&&plug2){
if(y!=m) cmax(f[now][state],val+c[x][y]);
if(x!=n) set(state,y,plug2),set(state,y+,),cmax(f[now][state],val+c[x][y]);
}
else if(plug1==&&plug2==)
set(state,link(state,y+),),set(state,y,),set(state,y+,),cmax(f[now][state],val+c[x][y]);
else if(plug1==&&plug2==){
set(state,y,),set(state,y+,);
if(!state) cmax(ans,val+c[x][y]);
}
else if(plug1==&&plug2==) set(state,y,),set(state,y+,),cmax(f[now][state],val+c[x][y]);
else if(plug1==&&plug2==)
set(state,link(state,y),),set(state,y,),set(state,y+,),cmax(f[now][state],val+c[x][y]);
}
}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
scanf("%d",&c[i][j]);
f[].init(),f[][]=;
for(int i=;i<=n;++i){
for(int j=;j<=m;++j) solve(i,j);
if(i!=n){
int now=(i*m)&,tot=f[now].sz;
for(int j=;j<=tot;++j)
f[now].key[j]<<=;
}
}
printf("%lld\n",ans);
return ;
}

洛谷P3190 [HNOI2007]神奇游乐园(插头dp)的更多相关文章

  1. 洛谷 P3190 [HNOI2007]神奇游乐园 解题报告

    P3190 [HNOI2007]神奇游乐园 Description 给你一个 \(m * n\) 的矩阵,每个矩阵内有个权值\(V(i,j)\) (可能为负数),要求找一条回路,使得每个点最多经过一次 ...

  2. bzoj 1187: [HNOI2007]神奇游乐园 插头dp

    1187: [HNOI2007]神奇游乐园 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 668  Solved: 337[Submit][Statu ...

  3. 【BZOJ1187】[HNOI2007]神奇游乐园 插头DP

    [BZOJ1187][HNOI2007]神奇游乐园 Description 经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细 ...

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

    题面: 传送门 给定一个四联通棋盘图,每个格子有权值,求一条总权值最大的回路 思路: 插头dp基础教程 棋盘? 回路? n,m<=10? 当然是插头dp啦~\(≧▽≦)/~ 然后发现这道题并不是 ...

  5. P3190 [HNOI2007]神奇游乐园

    传送门 第一道插头 $dp$ 由于讲不清楚所以假装各位早就会插头 $dp$ 了 首先要的是一个闭合回路,所以可以用括号表示法表示状态,然后大力分类讨论 $1.$ 没有右插头和下插头 那么我们可以啥也不 ...

  6. 洛谷P3272 [SCOI2011]地板(插头dp)

    传送门 感谢大佬的教导->这里 容易注意到,本题的合法路径“L型地板”有一些特殊的地方:拐弯且仅拐弯一次. 这由于一条路径只有两种状态:拐弯过和没拐弯过,因此我们可以尝试着这样定义新的插头: 我 ...

  7. 洛谷P2289 [HNOI2004]邮递员(插头dp)

    传送门 太神仙了……讲不来讲不来->这里 //minamoto #include<iostream> #include<cstdio> #include<cstri ...

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

    bzoj-1187 HNOI-2007 神奇游乐园 题目大意:经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这 ...

  9. 洛谷P2507 [SCOI2008]配对 题解(dp+贪心)

    洛谷P2507 [SCOI2008]配对 题解(dp+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1299251 链接题目地址:洛谷P2507 [S ...

随机推荐

  1. Database: key

    super-key: Any key that has more columns than necessary to uniquely identify each row in the table i ...

  2. Exception of type 'System.OutOfMemoryException' was thrown

    最近刚换了服务器,开始测试的时候未发现什么问题,可是一旦同一时间段操作的人比较多的时候,就会抛出如下错误: Server Error in '/' Application. Exception of ...

  3. RK平台images打包细则【转】

    本文转载自;https://blog.csdn.net/wangxueming/article/details/52808739 IMGs打包细节 平台: RK3288 背景: RK3288编译产生了 ...

  4. process调用protothread机制的相关宏定义——用HelloWorld进程诠释

    一.HelloWorld例子 #include "contiki.h" #include <stdio.h> /* For printf() */ /*-------- ...

  5. C/C++连接查询MYSQL

    1. [代码][C/C++]代码 #include <mysql/mysql.h>#include <stdio.h>#include <string.h>int ...

  6. BZOJ 1651 [Usaco2006 Feb]Stall Reservations 专用牛棚:优先队列【线段最大重叠层数】

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1651 题意: 给你n个线段[a,b],问你这些线段重叠最多的地方有几层. 题解: 先将线段 ...

  7. Struts2 输入校验 第四弹

    ActionSupport 里面有一个validate.可以重写里面你的方法. 校验执行流程: 1)首先进行类型转化 2)然后进行输入校验(执行validate方法) 3)如果在上述过程中出现了任何错 ...

  8. python 3 - 写一个注册的程序,账号和密码都存在文件里面

    choice = input('请输入你的选择:1,注册2.删除用户3.登录') #注册 输入 账号 密码 密码确认 # #需要校验用户是否存在,两次输入的密码,是否一致,为空的情况 #账号和密码都存 ...

  9. Java 吃货联盟

    import java.util.Scanner; public class Shao {  private static final int[] dishNames = null;  private ...

  10. Linux_异常_02_WinSCP上传文件时显示Permission denied

    异常现象如下: 二.解决方案 1.设置对应目录权限全开,就可以上传文件到这个目录了 sudo chmod 777 /devloper