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

  分类讨论独立插头:

  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. E - Is It A Tree? 并查集判断是否为树

    题目链接:https://vjudge.net/contest/271361#problem/E 具体思路:运用并查集,每一次连接上一个点,更新他的父亲节点,如果父亲节点相同,则构不成树,因为入读是2 ...

  2. Window 平台安装 Python:

    Window 平台安装 Python: 打开WEB浏览器访问http://www.python.org/download/ 在下载列表中选择Window平台安装包,包格式为:python-XYZ.ms ...

  3. idea docker 连接 linux 上的 docker

    安装插件 Docker插件,首先需要在你的IDEA中安装Docker插件,定位到File-Setting-Plugins后搜索Docker Integration安装 配置Docker服务器,在IDE ...

  4. CRF++进行中文分词实例

    工具包:https://taku910.github.io/crfpp/#tips 语料:http://sighan.cs.uchicago.edu/bakeoff2005/ 安装: 1)下载linu ...

  5. windos8设置cpu数量和内存大小

    转自:http://smilejay.com/2012/03/windows_cpu_memory_setting/ Windows 8(测试版)在作为Xen Guest中的benchmark测试.我 ...

  6. screen命令使用方法【转】

    在linux的环境中,我们想要在后台持续运行一些脚本,但是又因为关闭这个tty的话,脚本就会中断,这个时候我们就需要screen这个工具的帮助啦! 基础   1 首先先查看下否则有这个工具.如果运行s ...

  7. spring data jpa条件分组查询及分页

    原book对象 package com.shaying.domain; import javax.persistence.Column; import javax.persistence.Entity ...

  8. django 项目中的 favicon.ico 处理

    django 项目中的 favicon.ico 处理  (django == 2.0.6) 1. 引入模块: from django.views.generic.base import Redirec ...

  9. numpy基础代码操练

    In [20]: b[0,:,1] Out[20]: array([1, 5, 9]) In [21]: b[0,:,1] Out[21]: array([1, 5, 9]) In [22]: b[0 ...

  10. python平均值和加权平均值

    In [15]: import numpy as np In [16]: a=(70,80,60) In [17]: np.mean(a) #平均值 Out[17]: 70.0 In [18]: np ...