ZOJ 3213
/*
ZOJ 3213 好吧,看过那种括号表示法后,就崩溃了,实在受不了。情况复杂,写了两天,人也有点傻X了,只能放弃,转而用最小表示法。
最小表示法不难写: 1)首先,要承认路径上有格子不选的情况,于是,在00的情况下,可扩展,也可不选。
2)不能出现环,因而不能有L=U的情况出现。
3)以下是模版代码,类同是必然。但转而求路径数的时候,应当去掉不扩展的情况,同时,在IF(L|U)的情况下,亦不必考虑当前是否为最后一个格子,
只需按写的转移即可。
4)增加独立插头时,必须在总的独立插头数小于2的情况下进行。 注意:之所以不能出现两个插头,是因为,独立插头是单向的路径,不能进了又出。限制这个条件是非常有必要的。而在此处我本以为若限制了条件就得不出
最优解,而其实,因为存在不选的状态,限制了这个条件依然是可以有最优解的。
*/
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std; const int MAXD=;
const int HASH=;
const int STATE=; int N,M;
int maze[MAXD][MAXD];
int code[MAXD];
int ch[MAXD];
int num;
int ans; struct HASHMAP
{
int head[HASH],next[STATE],size;
int state[STATE],dp[STATE];
void init()
{
size=;
memset(head,-,sizeof(head));
}
void push(int st,int ans)
{
int i,h=st%HASH;
for(i=head[h];i!=-;i=next[i])
if(state[i]==st)
{
if(dp[i]<ans)dp[i]=ans;
return;
}
state[size]=st;
dp[size]=ans;
next[size]=head[h];
head[h]=size++;
}
}hm[];
void decode(int *code,int m,int st)
{
num=st&;//??????
st>>=;
for(int i=m;i>=;i--)
{
code[i]=st&;
st>>=;
}
}
int encode(int *code,int m)
{
int cnt=;
memset(ch,-,sizeof(ch));
ch[]=;
int st=;
for(int i=;i<=m;i++)
{
if(ch[code[i]]==-)ch[code[i]]=cnt++;
code[i]=ch[code[i]];
st<<=;
st|=code[i];
}
st<<=;
st|=num;
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<hm[cur].size;k++)
{
decode(code,M,hm[cur].state[k]);
left=code[j-];
up=code[j];
if(left&&up)
{
if(left!=up)
{
code[j-]=code[j]=;
for(int t=;t<=M;t++)
if(code[t]==up)
code[t]=left;
if(j==M)shift(code,M);
hm[cur^].push(encode(code,M),hm[cur].dp[k]+maze[i][j]);
}
}
else if(left||up)
{
int t;
if(left)t=left;
else t=up;
if(maze[i][j+])
{
code[j-]=;
code[j]=t;
hm[cur^].push(encode(code,M),hm[cur].dp[k]+maze[i][j]);
}
if(maze[i+][j])
{
code[j-]=t;
code[j]=;
hm[cur^].push(encode(code,j==M?M-:M),hm[cur].dp[k]+maze[i][j]);
}
if(num<) //封住一端,增加一个独立插头。
{
num++;
code[j-]=code[j]=;
hm[cur^].push(encode(code,j==M?M-:M),hm[cur].dp[k]+maze[i][j]);
}
}
else
{
code[j-]=code[j]=; //讨论简单路径,只需不讨论不选的情况就可以了。
hm[cur^].push(encode(code,j==M?M-:M),hm[cur].dp[k]);
if(maze[i][j+]&&maze[i+][j])
{
code[j-]=code[j]=;
hm[cur^].push(encode(code,M),hm[cur].dp[k]+maze[i][j]);
}
if(num<)
{
num++;
if(maze[i][j+])
{
code[j]=;
code[j-]=;
hm[cur^].push(encode(code,M),hm[cur].dp[k]+maze[i][j]);
}
if(maze[i+][j])
{
code[j-]=;
code[j]=;
hm[cur^].push(encode(code,j==M?M-:M),hm[cur].dp[k]+maze[i][j]);
}
}
}
}
}
void dpblock(int i,int j,int cur)
{
int k;
for(k=;k<hm[cur].size;k++)
{
decode(code,M,hm[cur].state[k]);//?????!!!
code[j-]=code[j]=;
if(j==M)shift(code,M);
hm[cur^].push(encode(code,M),hm[cur].dp[k]);
}
}
void init()
{
scanf("%d%d",&N,&M);
ans=;
memset(maze,,sizeof(maze));//???????
for(int i=;i<=N;i++)
for(int j=;j<=M;j++)
{
scanf("%d",&maze[i][j]);
if(maze[i][j]>ans)ans=maze[i][j];
}
}
void solve()
{
int i,j,cur=;
hm[cur].init();
hm[cur].push(,);
for(i=;i<=N;i++)
for(int j=;j<=M;j++)
{
hm[cur^].init();
if(maze[i][j])dpblank(i,j,cur);
else dpblock(i,j,cur);
cur^=;
}
for(i=;i<hm[cur].size;i++)
if(hm[cur].dp[i]>ans)
ans=hm[cur].dp[i];
printf("%d\n",ans);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
solve();
}
return ;
}
更新代码,自写的。WA了N久,感觉有几个问题要注意一下:
应当初始化图为0;
记住在增加独立插头时,任何时候要考虑是否<2
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std; const int MAXD=;
const int MAXL=;
const int MAXH=;
int n,m;
int ans; int num;
int map[MAXD][MAXD];
int code[MAXD]; int pos[MAXD],stac[MAXD];
int tmp[MAXD]; struct HASHMAP{
int hash[MAXL],state[MAXH],next[MAXH];
int f[MAXH];
int size;
void init(){
size=;
memset(hash,-,sizeof(hash));
}
void push(int st,int anst) {
int h=st%MAXL;
for(int i=hash[h];i!=-;i=next[i]){
if(state[i]==st){
if(f[i]<anst){
f[i]=anst;
}
return ;
}
}
state[size]=st;
f[size]=anst;
next[size]=hash[h];
hash[h]=size++;
}
}hm[]; void decode(int st){
for(int i=m;i>=;i--){
int t=st&;
code[i]=t;
st=st>>;
}
} int fd_r(int j){
int top=-;
for(int i=;i<=m;i++){
if(code[i]==) continue;
else if(code[i]==){
++top;
pos[top]=i; stac[top]=code[i];
}
else if(code[i]==){
if(pos[top]==j) return i;
else top--;
}
}
}
int fd_l(int j){
int top=-;
for(int i=;i<=m;i++){
if(code[i]==) continue;
else if(code[i]==){
++top;
pos[top]=i; stac[top]=code[i];
}
else if(code[i]==){
if(i==j) return pos[top];
else top--;
}
}
} void dpblank(int i,int j,int cur){
int em;int tmpst; int ls,us,tts;
for(int e=;e<hm[cur].size;e++){
int st=hm[cur].state[e];
num=st&;
st>>=;
decode(st);
int left=code[j-],up=code[j];
ls=(m-j+)*; us=(m-j)*;
if(!left&&!up){
tmpst=(st^(left<<ls))^(up<<us);
if(j==m) tmpst=tmpst>>;
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[e]);
if(map[i+][j]>&&map[i][j+]>){
tmpst=(st^(left<<ls))^(<<ls);
tmpst=(tmpst^(up<<us))^(<<us);
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[e]+map[i][j]);
}
if(num<){
num++;
if(map[i][j+]>){
tmpst=(st^(left<<ls));
tmpst=(tmpst^(up<<us))^(<<us);
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[e]+map[i][j]);
}
if(map[i+][j]>){
tmpst=(st^(left<<ls))^(<<ls);
tmpst=(tmpst^(up<<us));
if(j==m) tmpst>>=;
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[e]+map[i][j]);
}
}
}
else if(left&&up){
if(left==&&up==){
int tt=fd_r(j);
tts=(m-tt)*;
tmpst=(st^(code[tt]<<tts))^(<<tts);
tmpst=(tmpst^(left<<ls));
tmpst=(tmpst^(up<<us));
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[e]+map[i][j]);
}
else if(left==&&up==){
int tt=fd_l(j-);
tts=(m-tt)*;
tmpst=(st^(code[tt]<<tts))^(<<tts);
tmpst=(tmpst^(left<<ls));
tmpst=(tmpst^(up<<us));
if(j==m) tmpst>>=;
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[e]+map[i][j]);
}
else if(left==&&up==){
tmpst=(st^(left<<ls));
tmpst=(tmpst^(up<<us));
if(j==m) tmpst>>=;
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[e]+map[i][j]);
}
else if(left==&&up==){
tmpst=(st^(left<<ls));
tmpst=(tmpst^(up<<us));
if(j==m) tmpst>>=;
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[e]+map[i][j]);
}
else if(left==&&up!=){
int tt;
if(up==) tt=fd_r(j);
else tt=fd_l(j);
tts=(m-tt)*;
tmpst=st^(left<<ls);
tmpst=tmpst^(up<<us);
tmpst=(tmpst^(code[tt]<<tts))^(<<tts);
if(j==m) tmpst>>=;
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[e]+map[i][j]);
}
else if(left!=&&up==){
int tt;
if(left==) tt=fd_r(j-);
else tt=fd_l(j-);
tts=(m-tt)*;
tmpst=st^(left<<ls);
tmpst=tmpst^(up<<us);
tmpst=(tmpst^(code[tt]<<tts))^(<<tts);
if(j==m) tmpst>>=;
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[e]+map[i][j]);
}
}
else{
int tt,cott;
if(left) tt=left;
else tt=up;
if(map[i][j+]>){
tmpst=st^(up<<us)^(tt<<us);
tmpst=tmpst^(left<<ls);
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[e]+map[i][j]);
}
if(map[i+][j]>){
tmpst=st^(left<<ls)^(tt<<ls);
tmpst=tmpst^(up<<us);
if(j==m) tmpst>>=;
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[e]+map[i][j]);
}
if(tt==&&num<){ //忘了限制条件<2,WA了N久。
tmpst=st^(left<<ls)^(up<<us);
if(j==m) tmpst>>=;
tmpst<<=;
tmpst|=(num+);
hm[cur^].push(tmpst,hm[cur].f[e]+map[i][j]);
}
if(left!=&&up!=&&num<){
int sp=(tt==left? j-: j);
tts=(m-sp)*;
if(tt==) cott=fd_r(sp);
else cott=fd_l(sp);
tmpst=st^(code[sp]<<tts)^(code[cott]<<((m-cott)*))^(<<((m-cott)*));
if(j==m) tmpst>>=;
num++;
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[e]+map[i][j]);
}
}
}
} void dpblock(int i,int j,int cur){
int em; int tmpst;
for(int k=;k<hm[cur].size;k++){
int st=hm[cur].state[k];
num=st&;
st>>=;
decode(st);
tmpst=st^(code[j]<<((m-j)*))^(code[j-]<<((m-j+)*));
if(j==m) tmpst>>=;
tmpst<<=;
tmpst|=num;
hm[cur^].push(tmpst,hm[cur].f[k]);
}
} void solve(){
int cur=,i;
hm[cur].init();
hm[cur].push(,);
for( i=;i<=n;i++){
for(int j=;j<=m;j++){
hm[cur^].init();
if(map[i][j]>) dpblank(i,j,cur);
else dpblock(i,j,cur);
cur=cur^;
}
}
for( i=;i<hm[cur].size;i++)
if(hm[cur].f[i]>ans) ans=hm[cur].f[i];
printf("%d\n",ans);
} int main(){
int T; int i,j;
scanf("%d",&T);
while(T--){
ans=;
scanf("%d%d",&n,&m);
memset(map,,sizeof(map));
for(i=;i<=n;i++){
for(j=;j<=m;j++){
scanf("%d",&map[i][j]);
if(map[i][j]>ans) ans=map[i][j];
}
}
solve();
}
return ;
}
ZOJ 3213的更多相关文章
- ZOJ 3213 Beautiful Meadow 简单路径 插头DP
简单路径的题目,其实就是在状态后面多记了有多少个独立插头. 分类讨论独立插头: 1.只存在上插头或者左插头,可以选择作为独立插头. 2.都不存在上插头和左插头,选择作为独立插头的同时要标号为新的连通块 ...
- 插头DP专题
建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议 ...
- 插头dp的几个模板
/* ural1519 求经过全部可行点的哈密顿回路的个数 括号匹配法,转移有点复杂,可是时间空间比較小 */ #include<cstdio> #include<cstring&g ...
- ZOJ People Counting
第十三届浙江省大学生程序设计竞赛 I 题, 一道模拟题. ZOJ 3944http://www.icpc.moe/onlinejudge/showProblem.do?problemCode=394 ...
- ZOJ 3686 A Simple Tree Problem
A Simple Tree Problem Time Limit: 3 Seconds Memory Limit: 65536 KB Given a rooted tree, each no ...
- ZOJ Problem Set - 1394 Polar Explorer
这道题目还是简单的,但是自己WA了好几次,总结下: 1.对输入的总结,加上上次ZOJ Problem Set - 1334 Basically Speaking ac代码及总结这道题目的总结 题目要求 ...
- ZOJ Problem Set - 1392 The Hardest Problem Ever
放了一个长长的暑假,可能是这辈子最后一个这么长的暑假了吧,呵呵...今天来实验室了,先找了zoj上面简单的题目练练手直接贴代码了,不解释,就是一道简单的密文转换问题: #include <std ...
- ZOJ Problem Set - 1049 I Think I Need a Houseboat
这道题目说白了是一道平面几何的数学问题,重在理解题目的意思: 题目说,弗雷德想买地盖房养老,但是土地每年会被密西西比河淹掉一部分,而且经调查是以半圆形的方式淹没的,每年淹没50平方英里,以初始水岸线为 ...
- ZOJ Problem Set - 1006 Do the Untwist
今天在ZOJ上做了道很简单的题目是关于加密解密问题的,此题的关键点就在于求余的逆运算: 比如假设都是正整数 A=(B-C)%D 则 B - C = D*n + A 其中 A < D 移项 B = ...
随机推荐
- Vue中nextTick()解析
最近,在开发的时候遇到一个问题,让我对vue中nextTick()的用法加深了了解- 下面是在组件中引用的一个拖拽的组件: <vue-draggable-resizable class=&quo ...
- 51nod1446 Kirchhoff矩阵+Gauss消元+容斥+折半DFS
思路: //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using ...
- Unicode gbk gb2312 编码问题 [转载]
原文地址: http://www.cnblogs.com/csn0721/archive/2013/01/24/2875613.html HTML5 UTF-8 中文乱码 <!DOCTYPE ...
- ClouderaManager与CDH
* ClouderaManager与CDH 集群简述 对于企业而言,一般的集群大小规模大概是如下映射关系: 集群大小 小:10~30节点 中:100~300节点 大:1000+节点 对应所需的zook ...
- Java系列学习(十)-包与权限修饰符
1.形式参数和返回值的问题 (1)形式参数: A:类名:需要该类的对象 B:抽象类名:需要改类的子类对象 C:接口名:需要该接口的实现对象 (2)返回值类型: A:类名:抽象类名:返回的是该类的对象 ...
- MVC系列学习(八)-分布视图
1.本次学习实例 1.1.建议:为了尽可能让项目简单,就新建一个空的mvc项目,同时添加任何视图不用模板页 1.2注意:在添加LoginPart的分部视图时,要记得沟一个沟 2.项目代码,如下 总共三 ...
- iOS CoreData 开发之数据模型关系
接着上一篇,上一篇中,我们简单的实现了一个用户实体,本次添加一个用户信息实体,与用户实体相关联,关系为1:1. 新建一个实体UserInfo:
- Hive扩展功能(五)--HiveServer2服务高可用
软件环境: linux系统: CentOS6.7 Hadoop版本: 2.6.5 zookeeper版本: 3.4.8 主机配置: 一共m1, m2, m3这五部机, 每部主机的用户名都为centos ...
- #1003 Max Sum
http://acm.hdu.edu.cn/showproblem.php?pid=1003 给你一串数列,让你求出其中 一段连续的子数列 并且 该子数列所有数字之和最大,输出该子数列的和.起点与终点 ...
- linux杀掉某个进程的脚本
https://www.cnblogs.com/zeng1994/p/13a2c5a28e55dd3abc2c75a4fb80371a.html awk的说明: https://www.cnblogs ...