题意:有一个n*m的矩阵,每个格子中有一个值(可能负值),要从左上角走到右下角,求路径的最大花费。

思路:

  除了起点和终点外,其他的点可以走,也可以不走。

  (2)我用的是括号表示法,所以起始状态为')',即仅有一个右括号,那么到右下角也应该是只有一个右括号。因为,如果碰到()),加粗表示起点的那个右括号,那么合并后变成)##,仍然是右括号,如果是)(),那么合并后变成##),仍然是右括号,相当于延续了。插头每到达一个格子就先将其值给加上,如果要合并的时候,再减掉(因为多算了一次),因此,新括号的出现,就需要多加上3个格子的值了。

  (2)还有一个更直观的办法,就是添加半个圈,从起点到终点,设他们都为必走的格子,那就跟FZU 1977 PANDORA ADVENTURE (插头DP,常规)差不多了,只是没有了障碍格子而已。

  比如矩阵:

  000

  000

  000

  可以建图为(其中b为必走的格子):

  bbbb

  b00b

  000b

  00bb

  由于不用这样建图也是很容易解决的,所以下面代码就不这样建图了。

 #include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N=;
int g[N][N], cur, n, m;
struct Hash_Map
{
static const int mod=;
static const int NN=;
int head[mod]; //桶指针
int next[NN]; //记录链的信息
LL status[NN]; //状态
LL value[NN]; //状态对应的DP值。
int size; void clear() //清除哈希表中的状态
{
memset(head, -, sizeof(head));
size = ;
} void insert(LL st, LL val) //插入状态st的值为val
{
int h = st%mod;
for(int i=head[h]; i!=-; i=next[i])
{
if(status[i] == st) //这个状态已经存在,累加进去。
{
value[i] = max(value[i], val);
return ;
}
} status[size]= st; //找不到状态st,则插入st。
value[size] = val;
next[size] = head[h] ; //新插入的元素在队头
head[h] = size++;
}
}hashmap[]; inline int getbit(LL s,int pos) //取出状态s的第pos个插头
{
return (s>>*pos)&;
}
inline int setbit(LL s,int pos,int bit) //将状态s的第pos个插头设置为bit
{
if(s&(<<*pos )) s^=<<(*pos);
if(s&(<<(*pos+))) s^=<<(*pos+);
return (s|(bit<<*pos));
} int Fr(LL s,int pos,int bit) //寻找状态s的第pos个插头对应的右括号。
{
int cnt=;
for(pos+=; pos<m; pos++)
{
if(getbit(s, pos)==-bit) cnt++;
if(getbit(s, pos)==bit) cnt--;
if(cnt==-) return setbit(s, pos, -bit);
}
}
int Fl(LL s,int pos,int bit) //寻找状态s的第pos个插头对应的左括号。
{
int cnt=;
for(pos--; pos>=; pos--)
{
if(getbit(s, pos)==-bit) cnt++;
if(getbit(s, pos)==bit) cnt--;
if( cnt==-) return setbit(s, pos, -bit);
}
}
LL ans;
void DP(int i,int j)
{
for(int k=; k<hashmap[cur^].size; k++)
{
LL s=hashmap[cur^].status[k];
LL v=hashmap[cur^].value[k];
int R=getbit(s, j), D=getbit(s, j+);
LL t=(setbit(s,j,)&setbit(s,j+,));
if(R && D) //两个括号
{ if(R==D) //同个方向的括号
{
if(R==) t=Fr(t, j, ); //要改
else t=Fl(t, j, );
hashmap[cur].insert(t, v-g[i][j]);
}
else if( R== && D== ) //不同的连通分量
hashmap[cur].insert(t, v-g[i][j]);
}
else if(R || D) //仅1个括号
{
if( i+==n && j+==m && t== && ( R== || D== ) ) //终点才能闭合
ans=max(ans, v);
if(R) //右插头
{
if(i+<n ) hashmap[cur].insert(s, v+g[i+][j]);//往下
if(j+<m ) hashmap[cur].insert(setbit(t,j+,R), v+g[i][j+]);//往右
}
else //下插头
{
if(j+<m ) hashmap[cur].insert(s, v+g[i][j+]); //往右
if(i+<n ) hashmap[cur].insert(setbit(t,j,D), v+g[i+][j]);//往下
}
}
else
{
if( i+j ) hashmap[cur].insert(s, v); //不装括号
if( j+<m && i+<n && i+j ) //新括号
hashmap[cur].insert( setbit(s,j,)|setbit(s,j+,), v+g[i][j]+g[i+][j]+g[i][j+]);
}
}
} void cal()
{
for(int i=; i<n; i++)
{
cur^=;
hashmap[cur].clear();
for(int j=; j<hashmap[cur^].size; j++) //新行,需要左移一下状态。
hashmap[cur].insert( hashmap[cur^].status[j]<<, hashmap[cur^].value[j] );
for(int j=; j<m; j++)
{
cur^=;
hashmap[cur].clear();
DP(i,j);
}
}
} int main()
{
//freopen("input.txt", "r", stdin);
int Case=;
while(~scanf("%d%d",&n,&m))
{
memset(g, , sizeof(g));
ans=-INF; //注意
cur=;
for(int i=; i<n; i++) //输入
for(int j=; j<m; j++)
scanf("%d",&g[i][j]); hashmap[cur].clear();
hashmap[cur].insert(, g[][]);
cal();
printf("Case %d: %lld\n", ++Case, ans);
}
return ;
}

AC代码

HDU 3377 Plan (插头DP,变形)的更多相关文章

  1. HDU 3377 Plan

    Problem Description One day, Resty comes to an incredible world to seek Eve -- The origin of life. L ...

  2. HDU 4285 circuits( 插头dp , k回路 )

    circuits Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  3. 插头DP专题

    建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议 ...

  4. 插头dp练习

    最近学了插头dp,准备陆续更新插头dp类练习. 学习论文还是cdq那篇<基于连通性状态压缩的动态规划问题>. 基本的想法都讲得很通透了,接下来就靠自己yy了. 还有感谢kuangbin大大 ...

  5. HDU 4113 Construct the Great Wall(插头dp)

    好久没做插头dp的样子,一开始以为这题是插头,状压,插头,状压,插头,状压,插头,状压,无限对又错. 昨天看到的这题. 百度之后发现没有人发题解,hust也没,hdu也没discuss...在acm- ...

  6. HDU 4064 Carcassonne(插头DP)(The 36th ACM/ICPC Asia Regional Fuzhou Site —— Online Contest)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4064 Problem Description Carcassonne is a tile-based ...

  7. hdu 1693 Eat the Trees——插头DP

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1693 第一道插头 DP ! 直接用二进制数表示状态即可. #include<cstdio> # ...

  8. HDU 4949 Light(插头dp、位运算)

    比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题.. 因为写完之后,无限TLE... 直到后来用位运算代替了我插头dp常用的decode.encode.shift三个函数以 ...

  9. HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)

    插头DP基础题的样子...输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物.输出哈密顿回路(可以多回路)方案数... 看了个ppt,画了下图...感觉还是挺有效的... 参考 ...

随机推荐

  1. AngularJS系统学习之Scope(作用域)

    本文出自:https://www.w3ctech.com/topic/1611 看完了没怎么懂,  也许是和别人 原文作者: Nicolas Bhttps://www.w3ctech.com/topi ...

  2. wp8环境搭建

    Windows Phone 8将采用与Windows 8相同的NT内核,这就意味着WP8将可能兼容Win8应用,开发者仅需很少改动就能让应用在两个平台上运行.由于内核变更,Windows Phone  ...

  3. Bean的不同配置方式比较与应用场景

    基于XML配置 Bean的定义:           在XML文件中通过<bean>元素定义. Bean的名称:           通过<bean>的id或name属性定义. ...

  4. Hue离线安装

    参考 https://blog.csdn.net/xuxudede1989/article/details/50359023 http://cloudera.github.io/hue/latest/ ...

  5. PHP实用小程序(四)

    <HTML> <HEAD> <TITLE>访问文件时间属性</TITLE> </HEAD> <BODY> <? $Last ...

  6. 1118 Birds in Forest (25 分)

    Some scientists took pictures of thousands of birds in a forest. Assume that all the birds appear in ...

  7. TP5之页面跳转样式

    1.效果图 2.上干货 为了增加对移动设备的支持,在  /application/common.php加入以下函数: function isMobile() { if (isset ($_SERVER ...

  8. lightoj 1074【spfa判负环】

    题意: 给你一幅图,dis(u->v)的权值就是(w[v]-w[u])*(w[v]-w[u])*(w[v]-w[u]),所以有可能是负的,给你n个询问,给出最短路,长度<3或者不可达输出& ...

  9. lightoj 1034【强连通+缩点】

    思路: 缩点,计算入度为0点的个数即可: #include<bits/stdc++.h> using namespace std; typedef long long LL; const ...

  10. Android真机调测Profiler

    U3D中的Profile也是可以直接在链接安卓设备运行游戏下查看的,导出真机链接U3D的Profile看数据,这样能更好的测试具体原因. 大概看了下官方的做法,看了几张帖子顺带把做法记录下来. 参考: ...