简单路径的题目,其实就是在状态后面多记了有多少个独立插头。

  分类讨论独立插头:

  1、只存在上插头或者左插头,可以选择作为独立插头。

  2、都不存在上插头和左插头,选择作为独立插头的同时要标号为新的连通块。

  换行时需特别注意,因为还有独立插头的判断,如果进行了换行操作,就会乱,特别是在不存在上插头和左插头的情况下。

  那要怎么办呢?

  我们会发现,换行后,1~m-1往后移,并把code[0]设为0,但我们在encode的时候,code[0] = 0,其实是可以忽略的操作,那么我们只需要做M-1就可以了。

  这样想来,就可以去掉shift的操作了。

 #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm> using namespace std; #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define DWN(i, a, b) for (int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define mset(a, b) memset(a, b, sizeof(a))
const int MAXD = , HASH = , STATE = ;
int n, m, maze[MAXD][MAXD], code[MAXD], ch[MAXD];
int text[MAXD]; void Ckmax(int &AI, int BI) { if (AI < BI) AI = BI; } struct HASHMAP
{
int head[HASH], nxt[STATE], state[STATE], f[STATE], siz;
void clear() { siz = , mset(head, -); }
void push(int x, int add)
{
int pos = x%HASH, i = head[pos];
for (; i != -; i = nxt[i])
if (state[i] == x) { Ckmax(f[i], add); return ; }
state[siz] = x, f[siz] = add;
nxt[siz] = head[pos], head[pos] = siz++;
}
}hm[]; void in()
{
scanf("%d %d", &n, &m), mset(maze, );
REP(i, , n)
REP(j, , m) scanf("%d", &maze[i][j]);
} void decode(int x)
{
DWN(i, m+, ) code[i] = x&, x >>= ;
} int encode(int j)//WRONG 由于换行不能修改,要这样做
{
int ret = , cnt = , lim = (j == m) ? m- : m;
mset(ch, -), ch[] = ;
REP(i, , lim)
{
if (ch[code[i]] == -) ch[code[i]] = ++cnt;
ret <<= , ret |= ch[code[i]];
}
ret <<= , ret |= code[m+];
return ret;
} void dp_blank(int i, int j, int cur)
{
REP(k, , hm[cur].siz-)
{
decode(hm[cur].state[k]);
int lef = code[j-], up = code[j];
if (lef && up)
{
if (lef == up) continue ;
REP(t, , m)
if (code[t] == up) code[t] = lef;
code[j-] = code[j] = ;
hm[cur^].push(encode(j), hm[cur].f[k]+maze[i][j]);
}
else
{
if (lef || up)
{
int t = lef ? lef : up;
if (maze[i][j+])
{
code[j-] = , code[j] = t;
hm[cur^].push(encode(j), hm[cur].f[k]+maze[i][j]);
}
if (maze[i+][j])
{
code[j-] = t, code[j] = ;
hm[cur^].push(encode(j), hm[cur].f[k]+maze[i][j]);
}
if (code[m+]++ < )
{
code[j-] = code[j] = ;
hm[cur^].push(encode(j), hm[cur].f[k]+maze[i][j]);
}
}
else
{
hm[cur^].push(encode(j), hm[cur].f[k]);
if (maze[i][j+] && maze[i+][j])//WRONG
{
code[j-] = code[j] = ;
hm[cur^].push(encode(j), hm[cur].f[k]+maze[i][j]);
}
if (code[m+]++ > ) continue ;
if (maze[i][j+])
{
code[j-] = , code[j] = ;
hm[cur^].push(encode(j), hm[cur].f[k]+maze[i][j]);
}
if (maze[i+][j])
{
code[j-] = , code[j] = ;
hm[cur^].push(encode(j), hm[cur].f[k]+maze[i][j]);
}
}
}
}
} void dp_block(int i, int j, int cur)
{
REP(k, , hm[cur].siz-)
{
decode(hm[cur].state[k]);
code[j-] = code[j] = ;
hm[cur^].push(encode(j), hm[cur].f[k]);
}
} void work()
{
int cur = , ans = ;
hm[].clear(), hm[].clear(), hm[].push(, );
REP(i, , n)
REP(j, , m)
{
if (maze[i][j]) dp_blank(i, j, cur);
else dp_block(i, j, cur);
hm[cur].clear(), cur ^= ;
Ckmax(ans, maze[i][j]);
}
REP(i, , hm[cur].siz-) Ckmax(ans, hm[cur].f[i]);
printf("%d\n", ans);
} int main()
{
int T;
scanf("%d", &T);
while (T --) in(), work();
return ;
}

ZOJ 3213 Beautiful Meadow 简单路径 插头DP的更多相关文章

  1. ZOJ 3256 Tour in the Castle 插头DP 矩阵乘法

    题解 这题是一道非常好的插头题,与一般的按格转移的题目不同,由于m很大,要矩阵乘法,这题需要你做一个按列转移的插头DP. 按列转移多少与按格转移不同,但大体上还是基于连通性进行转移.每一列只有右插头是 ...

  2. zoj 2850 Beautiful Meadow

    Beautiful Meadow Time Limit: 2 Seconds      Memory Limit: 65536 KB Tom's Meadow Tom has a meadow in ...

  3. ZOJ 3466 The Hive II (插头DP,变形)

    题意:有一个n*8的蜂房(6边形的格子),其中部分是障碍格子,其他是有蜂蜜的格子,每次必须走1个圈取走其中的蜂蜜,在每个格子只走1次,且所有蜂蜜必须取走,有多少种取法? 思路: 以前涉及的只是n*m的 ...

  4. 插头DP专题

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

  5. 插头dp的几个模板

    /* ural1519 求经过全部可行点的哈密顿回路的个数 括号匹配法,转移有点复杂,可是时间空间比較小 */ #include<cstdio> #include<cstring&g ...

  6. hdu1693:eat trees(插头dp)

    题目大意: 题目背景竟然是dota!屠夫打到大后期就没用了,,只能去吃树! 给一个n*m的地图,有些格子是不可到达的,要把所有可到达的格子的树都吃完,并且要走回路,求方案数 题解: 这题大概是最简单的 ...

  7. P3170-[CQOI2015]标识设计【插头dp】

    正题 题目链接:https://www.luogu.com.cn/problem/P3170 题目大意 给出\(n*m\)的网格上有一些障碍,要求用三个\(L\)形(高宽随意,不能退化成线段/点)覆盖 ...

  8. 【插头dp】CDOJ1690 这是一道比CCCC简单题难的简单题

    最裸的插头dp,可参见大白书. #include<cstdio> #include<cstring> using namespace std; #define MOD 1000 ...

  9. ZOJ 3213

    /* ZOJ 3213 好吧,看过那种括号表示法后,就崩溃了,实在受不了.情况复杂,写了两天,人也有点傻X了,只能放弃,转而用最小表示法. 最小表示法不难写: 1)首先,要承认路径上有格子不选的情况, ...

随机推荐

  1. 【总结】前端必须收藏的CSS3动效库!!!

    现在的网站和App的设计中越来越重视用户体验,而优秀的动效则能使你的应用更具交互性,从而吸引更多用户的使用. 如果你对CSS3中定义动效还不熟练,或希望采用更加简单直接的方式在你的应用中引入动效的话, ...

  2. C# 操作资源文件

    (1)首先引用这两个命名空间 (2)两种方式调用资源文件中的内容 private void button2_Click(object sender, EventArgs e) { //通过Resour ...

  3. 安装Docker-ce

    Docker Engine改为Docker CE(社区版) 它包含了CLI客户端.后台进程/服务以及API.用户像以前以同样的方式获取.Docker Data Center改为Docker EE(企业 ...

  4. 树莓派开发系列教程3--ssh、vnc远程访问

    注意:树莓派系列的3篇文章里面的图片因为博客转移过程丢失了,非常抱歉 前言 远程访问有很多种方式可以实现.比如ssh.telnet.ftp.samba.远程桌面等等,各有优缺点.本文主要以ssh和远程 ...

  5. Python3中对Dict的内存优化

    众所周知,python3.6这个版本对dict的实现是做了较大优化的,特别是在内存使用率方面,因此我觉得有必要研究一下最新的dict的源码实现. 前后断断续续看了大概一周多一点,主要在研究dict和创 ...

  6. Linux搭建svn服务

    svn是为了方便代码进行版本控制 Linux)svn服务器 --> windows) svn访问端 ********* [root@svn ~]# yum install -y subversi ...

  7. /proc/mounts介绍

    现在的 Linux 系统里一般都有这么三个文件:/etc/fstab,/etc/mtab,和 /proc/mounts,比较容易让人迷惑.简单解释一下. /etc/fstab 是只读不写的,它提供的是 ...

  8. CGIC简明教程(转摘)

    CGIC简明教程 本系列的目的是演示如何使用C语言的CGI库“CGIC”完成Web开发的各种要求. *********************************     基础知识       1 ...

  9. Bootstrap开发模板

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8& ...

  10. POJ 1392 Ouroboros Snake(数位欧拉)

    题目链接:http://poj.org/problem?id=1392 题目大意:题意看的我头痛,其实跟HDU2894差不多,但是这题要求输出这条路径上第k个数,而不是输出路径. 解题思路:也跟HDU ...