Description

  对于一个n*m的地图,每个格子有五种可能:平地,障碍物,出口,入口和神器。一个有效的地图必须满足下列条件:

  1.入口,出口和神器都有且仅出现一次,并且不在同一个格子内。

  2.入口,出口和神器两两都是连通的。

  连通性判断为四连通。

  现在给出一个n*m的地图,其中一些格子的状态已经确定,另一些格子的状态未确定。

  问当所有的格子状态确定之后,有多少种情况使得该地图是一个有效的地图?输出结构为答案模1e9+7。

Input

  第一行输入两个整数n和m,意义如题目所示。接下来n行,每行m个字符:

  字符'.'表示平地

  字符'#'表示障碍物

  字符'?'表示未确定

  字符'S'表示入口

  字符'X'表示神器

  字符'E'表示出口

Output

  一行,表示方案数

Sample Input

  2 3

  S#E

  ???

Sample Output

  3

HINT

  对于30%的数据,?数量小于10

  对于100%的数据,1<=n<=7,1<=m<=7

Solution

  这是一道类插头DP的题目,做法与插头DP类似。

  对于'?',我们可以枚举情况;而对于其他已经确定了的状态,可以直接按格DP。

  状态只需记录格子所在的连通块,并在最后记录入口,出口和神器所在的连通块,HASH存。

Code

 #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))
typedef long long LL;
const int MAXD = , HASH = , STATE = , MOD = 1e9+;
int n, m, code[MAXD], ch[MAXD], x[], y[];
char maze[MAXD][MAXD], sp[] = {'S', 'X', 'E', '.', '#'}; void add(LL &x, LL y) { x += y; if (x >= MOD) x -= MOD; } struct HASHMAP
{
int head[HASH], nxt[STATE], siz; LL state[STATE], f[STATE];
void clear() { siz = , mset(head, -); }
void push(LL x, LL k)
{
int pos = x%HASH, i = head[pos];
for (; i != -; i = nxt[i])
if (state[i] == x) { add(f[i], k); return ; }
state[siz] = x, f[siz] = k;
nxt[siz] = head[pos], head[pos] = siz++;
}
}hm[]; void in()
{
scanf("%d %d", &n, &m);
mset(x, -), mset(y, -);
REP(i, , n)
{
scanf("%s", maze[i]+);
REP(j, , m)
{
if (maze[i][j] == 'S') x[] = i, y[] = j;
else if (maze[i][j] == 'X') x[] = i, y[] = j;
else if (maze[i][j] == 'E') x[] = i, y[] = j;
}
}
} bool check(int i, int j)
{
if (maze[i][j] == 'S' && code[m+]) return ;
else if (maze[i][j] == 'X' && code[m+]) return ;
else if (maze[i][j] == 'E' && code[m+]) return ;
else return ;
} void decode(LL x)
{
REP(i, , m+) code[i] = x&, x >>= ;
} LL encode(int i, int j)
{
if (maze[i][j] == 'S') code[m+] = code[j];
else if (maze[i][j] == 'X') code[m+] = code[j];
else if (maze[i][j] == 'E') code[m+] = code[j];
LL ret = ; int cnt = ;
mset(ch, -), ch[] = ;
DWN(t, m+, )
{
if (ch[code[t]] == -) ch[code[t]] = ++cnt;
ret <<= , ret |= ch[code[t]];
}
return ret;
} void dp_blank(int i, int j, int cur)
{
REP(k, , hm[cur].siz-)
{
decode(hm[cur].state[k]);
if (check(i, j)) continue ;
int lef = code[j-], up = code[j], id = ;
if (lef) id = min(id, lef);
if (up) id = min(id, up);
if (lef)
REP(t, , m+) if (code[t] == lef) code[t] = id;
if (up)
REP(t, , m+) if (code[t] == up) code[t] = id;
code[j] = id;
hm[cur^].push(encode(i, j), hm[cur].f[k]);
}
} void dp_block(int i, int j, int cur)
{
REP(k, , hm[cur].siz-)
{
decode(hm[cur].state[k]), code[j] = ;
hm[cur^].push(encode(i, j), hm[cur].f[k]);
}
} void work()
{
int cur = ; LL ans = ;
hm[].clear(), hm[].clear(), hm[].push(, );
REP(i, , n)
REP(j, , m)
{
if (maze[i][j] != '?')
{
if (maze[i][j] == '#') dp_block(i, j, cur);
else dp_blank(i, j, cur);
}
else
{
REP(t, , )
{
if (t < && x[t] != -) continue ;
maze[i][j] = sp[t];
if (maze[i][j] == '#') dp_block(i, j, cur);
else dp_blank(i, j, cur);
}
}
hm[cur].clear(), cur ^= ;
}
REP(i, , hm[cur].siz-)
{
decode(hm[cur].state[i]);
if ((!code[m+]) || (!code[m+]) || (!code[m+])) continue ;
int t = code[m+];
if (code[m+] != t || code[m+] != t) continue ;
add(ans, hm[cur].f[i]);
}
printf("%I64d\n", ans);
} int main()
{
in();
work();
return ;
}

【GDKOI 2016】地图 map 类插头DP的更多相关文章

  1. GDKOI 2016

    GDKOI 2016 day 1 第一题 魔卡少女 题目描述:维护一个序列,能进行以下两个操作:1.将某一个位置的值改变.2.求区间的连续子串的异或值的和. solution 因为序列的数的值都小于\ ...

  2. 插头dp练习

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

  3. UVA11270 Tiling Dominoes —— 插头DP

    题目链接:https://vjudge.net/problem/UVA-11270 题意: 用2*1的骨牌填满n*m大小的棋盘,问有多少种放置方式. 题解: 骨牌类的插头DP. 1.由于只需要记录轮廓 ...

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

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

  5. 插头DP专题

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

  6. hdu1693:eat trees(插头dp)

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

  7. 动态规划之插头DP入门

    基于联通性的状态压缩动态规划是一类非常典型的状态压缩动态规划问题,由于其压缩的本质并不像是普通的状态压缩动态规划那样用0或者1来表示未使用.使用两种状态,而是使用数字来表示类似插头的状态,因此.它又被 ...

  8. hdu1964之插头DP求最优值

    Pipes Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Subm ...

  9. ural1519插头DP

    1519. Formula 1 Time limit: 1.0 second Memory limit: 64 MB Background Regardless of the fact, that V ...

随机推荐

  1. js 获取格林尼治时间戳

    昨天在一论坛里看到有朋友问 js 如何获取格林尼治时间戳.不少朋友第一反应是 toGMTString ...确实可以得到格林尼治时间,但不是时间戳.虽然我也没有啥好的方法一步到位的获取,不过至少是获取 ...

  2. TED_Topic9:How we're priming some kids for college — and others for prison

    Alice Goffman In the United States, two institutions guide teenagers on the journey to adulthood: co ...

  3. 收集SpringBoot的一些学习资料

    1:wuyouzhuguli的博客  (24篇) https://github.com/wuyouzhuguli/Spring-Boot-Demos 2:方志鹏的博客  (27篇) https://b ...

  4. MySQL-视图View

    视图:一个非真实存在的,囊括复杂查询在内的表,也可以理解成,视图就是一个查询之后的结果. 补充一个概念:临时表查询(子查询):就是在查询语句中再次嵌套一个查询,并将嵌套中的查询设定别名 SELECT ...

  5. 利用iis虚拟目录实现文件服务器功能

    要求说明: 通过网站上传文件保存到统一的文件服务器上. 服务器说明: 1.文件服务器以下称为FilesServer,IP地址为:192.168.1.213 2.Web服务器为以下称为WebServer ...

  6. 获取同一接口多个实现类的bean

    @Service("taskExecutorFactory") public class TaskExecutorFactory implements ApplicationCon ...

  7. 配置Eclipse编写HTML/JS/CSS/JSP页面的自动提示

    我们平时用eclipse开发jsp页面时智能提示效果不太理想,今天用了两个小时发现了eclipse也可以像Visual Studio 2008那样完全智能提示HTML/JS/CSS代码,使用eclip ...

  8. JavaScript:document.execCommand()的用法

    document.execCommand()的用法小记 一.语法 execCommand方法是执行一个对当前文档,当前选择或者给出范围的命令.处理Html数据时常用. 如下格式:document.ex ...

  9. 字符串(string.cpp)

    字符串(string.cpp) 神TM字符串DP 题目描述: 小林和亮亮正在做一个游戏.小林随意的写出一个字符串,字符串仅由大写字母组成,然后指定一个非负整数m,亮亮可以进行至多m次操作.每次操作为交 ...

  10. 算法之DP

    一般DP 都是有模板的,先初始化,然后找到不同状态下数值的关系,使得某个状态可用另一个状态由一个固定的方式转移而来,列出状态转移方程,这就是DP: 例题 P1216 [USACO1.5]数字三角形 N ...