洛谷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写法和很多人不一样诶……)
//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)的更多相关文章
- 洛谷 P3190 [HNOI2007]神奇游乐园 解题报告
P3190 [HNOI2007]神奇游乐园 Description 给你一个 \(m * n\) 的矩阵,每个矩阵内有个权值\(V(i,j)\) (可能为负数),要求找一条回路,使得每个点最多经过一次 ...
- bzoj 1187: [HNOI2007]神奇游乐园 插头dp
1187: [HNOI2007]神奇游乐园 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 668 Solved: 337[Submit][Statu ...
- 【BZOJ1187】[HNOI2007]神奇游乐园 插头DP
[BZOJ1187][HNOI2007]神奇游乐园 Description 经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细 ...
- [HNOI2007][bzoj1187] 神奇游乐园 [插头dp]
题面: 传送门 给定一个四联通棋盘图,每个格子有权值,求一条总权值最大的回路 思路: 插头dp基础教程 棋盘? 回路? n,m<=10? 当然是插头dp啦~\(≧▽≦)/~ 然后发现这道题并不是 ...
- P3190 [HNOI2007]神奇游乐园
传送门 第一道插头 $dp$ 由于讲不清楚所以假装各位早就会插头 $dp$ 了 首先要的是一个闭合回路,所以可以用括号表示法表示状态,然后大力分类讨论 $1.$ 没有右插头和下插头 那么我们可以啥也不 ...
- 洛谷P3272 [SCOI2011]地板(插头dp)
传送门 感谢大佬的教导->这里 容易注意到,本题的合法路径“L型地板”有一些特殊的地方:拐弯且仅拐弯一次. 这由于一条路径只有两种状态:拐弯过和没拐弯过,因此我们可以尝试着这样定义新的插头: 我 ...
- 洛谷P2289 [HNOI2004]邮递员(插头dp)
传送门 太神仙了……讲不来讲不来->这里 //minamoto #include<iostream> #include<cstdio> #include<cstri ...
- [bzoj1187][HNOI2007]神奇游乐园_插头dp
bzoj-1187 HNOI-2007 神奇游乐园 题目大意:经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这 ...
- 洛谷P2507 [SCOI2008]配对 题解(dp+贪心)
洛谷P2507 [SCOI2008]配对 题解(dp+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1299251 链接题目地址:洛谷P2507 [S ...
随机推荐
- JS性能优化——加载和执行
JavaScript 在浏览器中的性能,可以认为是开发者所面临得最严重的可用性问题.这个问题因JavaScript的阻塞特性变得复杂, 也就是说当浏览器在执行JavaScript代码时,不能同时做其他 ...
- okhttp 请求list数据实例
public class DataBean { /** * id : 61684 * movieName : <猜火车2>先导预告片 * coverImg : http://img31.m ...
- JAVA线程sleep和wait方法区别 代码
package test; import java.util.Date; import java.util.Random; public class test { public static void ...
- leetcode 859. Buddy Strings
Given two strings A and B of lowercase letters, return true if and only if we can swap two letters i ...
- math worksheet作业纸生成器
https://www.education.com/worksheet-generator/math/ https://www.mathgoodies.com/worksheets/generator ...
- zabbix 监控 haproxy 记录
1. 当配置好后,遇到 Value should be a JSON object. 该如何是好? sudo 文件增加: zabbix ALL=(ALL) NOPASSWD: ALL haproxy ...
- 如何用命令行删除EasyBCD开机选择项?
用硬盘安装Ubuntu方法的windows双系统电脑上面,很多人都是用EasyBCD设置的开机启动选择.所以当我们不需要双系统的时候,或者已经删除双系统后,或者安装双系统失败的情况下,发现电脑的开机启 ...
- db2move 数据导出整理
db2move <database-name> <action> [<option> <value>] 命令解释:1).database-name, ...
- listen 71
Creepy People Leave You Cold Jack Nicholson, playing the crazed caretaker in The Shining, makes me r ...
- linux网络编程 gethostbyname()
gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针.结构的声明与gethostaddr()中一致. 返回对应于给定主机名的主机信息. #include ...