【GDKOI 2016】地图 map 类插头DP
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的更多相关文章
- GDKOI 2016
GDKOI 2016 day 1 第一题 魔卡少女 题目描述:维护一个序列,能进行以下两个操作:1.将某一个位置的值改变.2.求区间的连续子串的异或值的和. solution 因为序列的数的值都小于\ ...
- 插头dp练习
最近学了插头dp,准备陆续更新插头dp类练习. 学习论文还是cdq那篇<基于连通性状态压缩的动态规划问题>. 基本的想法都讲得很通透了,接下来就靠自己yy了. 还有感谢kuangbin大大 ...
- UVA11270 Tiling Dominoes —— 插头DP
题目链接:https://vjudge.net/problem/UVA-11270 题意: 用2*1的骨牌填满n*m大小的棋盘,问有多少种放置方式. 题解: 骨牌类的插头DP. 1.由于只需要记录轮廓 ...
- HDU 4113 Construct the Great Wall(插头dp)
好久没做插头dp的样子,一开始以为这题是插头,状压,插头,状压,插头,状压,插头,状压,无限对又错. 昨天看到的这题. 百度之后发现没有人发题解,hust也没,hdu也没discuss...在acm- ...
- 插头DP专题
建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议 ...
- hdu1693:eat trees(插头dp)
题目大意: 题目背景竟然是dota!屠夫打到大后期就没用了,,只能去吃树! 给一个n*m的地图,有些格子是不可到达的,要把所有可到达的格子的树都吃完,并且要走回路,求方案数 题解: 这题大概是最简单的 ...
- 动态规划之插头DP入门
基于联通性的状态压缩动态规划是一类非常典型的状态压缩动态规划问题,由于其压缩的本质并不像是普通的状态压缩动态规划那样用0或者1来表示未使用.使用两种状态,而是使用数字来表示类似插头的状态,因此.它又被 ...
- hdu1964之插头DP求最优值
Pipes Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Subm ...
- ural1519插头DP
1519. Formula 1 Time limit: 1.0 second Memory limit: 64 MB Background Regardless of the fact, that V ...
随机推荐
- Linux命令(六)Linux超级用户和管理组
修改文件目录的所属组
- .NET面试题系列(三)排序算法
冒泡排序 , , , , , 7, 2, 4 }; //外层循环控制排序趟数 ; i < arr.Length - ; i++) { //内层循环控制每一趟排序多少次 ; j < arr. ...
- chrome 隐藏技能之 base64 图片转换
有时候我们要转换图片为base64,或者将base64转回图片,可能都需要找一些在线工具或者软件类型的工具才行.当然 chrome 也算是软件,但是好在做前端的都有 chrome.好了,来看下简单的例 ...
- javascript类式继承最优版
直接看实例代码: <!doctype html> <html lang="en"> <head> <meta charset=" ...
- 20155314 2016-2017-2 《Java程序设计》第7周学习总结
20155314 2016-2017-2 <Java程序设计>第7周学习总结 教材学习内容总结 了解Lambda语法 了解方法引用 了解Fucntional与Stream API 掌握Da ...
- 20155339 2016-2017-2 《Java程序设计》第5周学习总结
20155339 2016-2017-2 <Java程序设计>第5周学习总结 教材学习内容总结 使用try.catch 使用try.catch语法,JVM会先尝试执行try区块中的代码,如 ...
- iOS数据库操作之coredata详细操作步骤
CHENYILONG Blog iOS数据库操作之coredata详细操作步骤 技术博客http://www.cnblogs.com/ChenYilong/ 新浪微博http://weibo.com/ ...
- python 入门基础23 选课系统 项目
选课系统 代码地址:github_code # 选课系统 # 角色:学校.学员.课程.讲师 # 要求: # 1. 创建北京.上海 2 所学校 # 2. 创建linux , python , go 3个 ...
- Java内存模型-final域的内存语义
一 引言 说到final你肯定知道它是Java中的关键字,那么它所在Java中的作用你知道吗?不知道的话,请前往这篇了解下https://www.cnblogs.com/yuanfy008/p/802 ...
- NET调用Com组件事例
http://blog.csdn.net/shizhiyingnj/article/details/1507948 在程序设计中,往往通过键盘的某个按键来完成相关操作! 下面就来说明如何实现: 1.引 ...