HDU 3377 插头dp
题目大意:
从左上角走到右下角,每个点之多经过一次,取到所有路径上经过点的权值,求最大的权值之和,这里走到右下角就算停止了
这里有个思路是转化成熟悉的回路问题
在上方和右方最外围定义一圈权值为0 , 那么我们相当于从定义以后的左上角开始经过所有外围点形成的回路,那么去掉最外围的0,剩下的就是(1,1)-》(n,n)的权值和了
但是这里最外围的点的插头具有特殊性,每次到最外围的点,你左和上有且仅有一个插头,而且出去的方向必然是下一个最外围的点
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream> using namespace std;
#define ll long long
const int HASH = ;
const int STATE = ;
const int MAXD = ;
int n , m;
int code[MAXD] , mp[MAXD][MAXD];
bool flag[MAXD][MAXD];//标记位,标记当前点能否作为最终点
ll ans = ;
int w[MAXD][MAXD];
struct HASHMAP{
int head[HASH] , next[STATE] , state[STATE] , size;
ll f[STATE]; void init(){
size = ;
memset(head , - , sizeof(head));
} void push_in(int st , ll sum){
int h = st%HASH;
for(int i = head[h] ; ~i ; i=next[i]){
if(st == state[i]){
f[i]=max(f[i] , sum); //这题目为求最大值
return ;
}
}
f[size]=sum;
state[size] = st;
next[size] = head[h];
head[h] = size++;
}
}hashmap[]; int num = ;//记录共有的插头数量
void decode(int *code , int m , int st)
{
num = ;
for(int i=m ; i>= ; i--){
code[i] = st&;
st>>=;
if(code[i]) num++;
}
} int encode(int *code , int m)
{
int st=;
for(int i= ; i<=m ; i++){
st<<=;
st |= code[i];
}
return st;
} void shift(int *code , int m) //换行,可理解为将最右侧轮廓线换到了下一行的最左侧
{
for(int i=m ; i>= ; i--) code[i] = code[i-];
code[] = ;
} void dpblank(int i , int j , int cur)
{
int k , left , up;
for(k= ; k<hashmap[cur].size ; k++){
decode(code , m , hashmap[cur].state[k]);
left = code[j-];
up = code[j];
if(!left && !up){
if(mp[i][j]==) continue;
if(mp[i][j]==){
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
}
if(mp[i][j+] && mp[i+][j]){
code[j-] = , code[j] = ;
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]+w[i][j]);
}
}
else if(!left && up){
if(mp[i][j]== && (up!=)) continue;
else if(mp[i][j]==){
if(mp[i][j+]==) hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]+w[i][j]);
else{
code[j-] = up , code[j] = ;
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]+w[i][j]);
}
continue;
}
if(mp[i][j+]) hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]+w[i][j]);
if(mp[i+][j]){
code[j-] = up , code[j] = ;
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]+w[i][j]);
}
}
else if(left && !up){
if(mp[i][j]== && (left!=)) continue;
else if(mp[i][j]==){
if(mp[i][j+]==){
code[j-] = , code[j] = left;
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]+w[i][j]);
}else{
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]+w[i][j]);
}
continue;
}
if(mp[i+][j]){
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]+w[i][j]);
}
if(mp[i][j+]){
code[j-] = , code[j] = left;
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]+w[i][j]);
}
}
else if(mp[i][j]==) continue;
else if(left== && up == ){
int cnt = ;
for(int v=j+ ; v<=m ; v++){
if(code[v]==)cnt++;
if(code[v]==)cnt--;
if(!cnt){
code[v]=;
break;
}
}
code[j-] = code[j] = ;
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]+w[i][j]);
}
else if(left == && up == ){
int cnt=;
for(int v=j- ; v>= ; v--){
if(code[v]==)cnt++;
if(code[v]==)cnt--;
if(!cnt){
code[v]=;
break;
}
}
code[j-] = code[j] = ;
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]+w[i][j]);
}
else if(left== && up==){
if(i==n && j==m) ans=max(ans,hashmap[cur].f[k]+w[i][j]);
}
else{
code[j-]=code[j]=;
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]+w[i][j]);
}
}
} void init()
{
for(int i= ; i<=m+ ; i++) mp[][i]= , w[][i] = ;
for(int i= ; i<=n+ ; i++){
for(int j= ; j<=m ; j++)
scanf("%d" , &w[i][j]) , mp[i][j]=;
w[i][m+] = , mp[i][m+] = ;
mp[i][m+] = mp[n+][i]=;
} n++ , m++;
mp[][] = mp[n][m] = ;
/*for(int i=1 ; i<=n ; i++){
for(int j=1 ;j <=m ; j++){
cout<<mp[i][j]<<" ";
}
cout<<endl;
}*/
} ll solve()
{
ans = -1e9;
int cur = ;
hashmap[cur].init();
hashmap[cur].push_in( , );
for(int i= ; i<=n ; i++){
for(int j= ; j<=m ; j++){
hashmap[cur^].init();
dpblank(i , j , cur);
cur ^= ;
/* cout<<"test: "<<i<<" "<<j<<endl;
for(int k=0 ; k<hashmap[cur].size ; k++)
cout<<hashmap[cur].f[k]<<endl;*/ }
}
// for(int i=0 ; i<hashmap[cur].size ; i++)
return ans;
} int main()
{
// freopen("in.txt" , "r" , stdin);
int cas = ;
while(~scanf("%d%d" , &n , &m))
{
init();
printf("Case %d: ",++cas);
if(n== && m==){
printf("%d\n" , w[][]);
continue;
}
printf("%I64d\n" , solve());
}
return ;
}
HDU 3377 插头dp的更多相关文章
- hdu 1693 插头dp入门
hdu1693 Eat the Trees 题意 在\(n*m\)的矩阵中,有些格子有树,没有树的格子不能到达,找一条或多条回路,吃完所有的树,求有多少种方法. 解法 这是一道插头dp的入门题,只需要 ...
- HDU 1693 插头dp入门详解
放题目链接 https://vjudge.net/problem/22021/origin 给出一个n*m的01矩阵,1可走0不可通过,要求走过的路可以形成一个环且可以有多个环出现,问有多少不同的 ...
- HDU 3377 Plan (插头DP,变形)
题意:有一个n*m的矩阵,每个格子中有一个值(可能负值),要从左上角走到右下角,求路径的最大花费. 思路: 除了起点和终点外,其他的点可以走,也可以不走. (2)我用的是括号表示法,所以起始状态为') ...
- HDU 4113 Construct the Great Wall(插头dp)
好久没做插头dp的样子,一开始以为这题是插头,状压,插头,状压,插头,状压,插头,状压,无限对又错. 昨天看到的这题. 百度之后发现没有人发题解,hust也没,hdu也没discuss...在acm- ...
- 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 ...
- hdu 1693 Eat the Trees——插头DP
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1693 第一道插头 DP ! 直接用二进制数表示状态即可. #include<cstdio> # ...
- HDU 4949 Light(插头dp、位运算)
比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题.. 因为写完之后,无限TLE... 直到后来用位运算代替了我插头dp常用的decode.encode.shift三个函数以 ...
- HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)
插头DP基础题的样子...输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物.输出哈密顿回路(可以多回路)方案数... 看了个ppt,画了下图...感觉还是挺有效的... 参考 ...
- HDU 1693 Eat the Trees(插头DP)
题目链接 USACO 第6章,第一题是一个插头DP,无奈啊.从头看起,看了好久的陈丹琦的论文,表示木看懂... 大体知道思路之后,还是无法实现代码.. 此题是插头DP最最简单的一个,在一个n*m的棋盘 ...
随机推荐
- Android 设置进度条背景
Android 设置进度条背景 直接上代码 <ProgressBar android:id="@+id/progressBar" android:layout_width=& ...
- return
return作为返回关键字,有以下两种意义的返回格式: 1,返回把握与函数成果:停止函数执行,返回调用函数,并且把函数的值作为返回成果. turn只能退出当前函数,如果多个函数嵌套就不行了,要想整个退 ...
- 自定义MVC Html
自定义ASP.NET MVC Html辅助方法 在ASP.NET MVC中,Html辅助方法给我们程序员带来很多方便,其重要性也就不言自明.有时候,我们不想重复地写一些HTML代码,或者MS没有提供我 ...
- ITERATOR(迭代器)设计模式
1 意图:提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示. 2 别名(Cursor) 3 动机:队列表的访问和遍历从列表对象中分离出来放入一个迭代器对象中. 多态迭代 ...
- Machine Learning – 第2周(Linear Regression with Multiple Variables、Octave/Matlab Tutorial)
Machine Learning – Coursera Octave for Microsoft Windows GNU Octave官网 GNU Octave帮助文档 (有900页的pdf版本) O ...
- js文字上下滚动代码
<div id="dome"> <div id="dome1"> <ul class="express"> ...
- JavaScript window
window -- window对象是BOM中所有对象的核心 window,中文"窗口" window对象除了是BOM中所有对象的父对象外,还包含一些窗口控制函数 全局的windo ...
- 【CITE】利用鼠标绘图C#
实例018 利用鼠标绘图 光盘位置:光盘\MR\01\018 在常用的画图软件中,用户一般都可以通过鼠标在其中绘图,那么该功能是如何实现的呢?本实例将讲解如何使用C#实现通过拖动鼠标在窗体上绘图的功能 ...
- Python--关于 join 和 split
.join() join将 容器对象 拆分并以指定的字符将列表内的元素(element)连接起来,返回字符串(注:容器对象内的元素须为字符类型) >>> a = ['no','pai ...
- java之多线程(Thread)
package DEMO; //主线程 public class Example12_2 { public static void main(String [] args ) { Thread myd ...