题面

Source:

unordered_map:

#include <iostream>
#include <tr1/unordered_map>
#include <cstdio>
#include <cstring> using namespace std; const int maxM = 200005; #define LL long long char mp[20][20];
int c[4] = {0, -1, 1, 0};
int n, m, ex, ey;
tr1::unordered_map<int, LL> Ht[2], T; int now;
int set(int state, int x, int val) //使状态的第x位变成val
{ x <<= 1; return (state & (~(3<<x))) | (val << x); }
int get(int state, int x) //得到转态的第x位
{ x <<= 1; return (state >> x) & 3; }
int getl(int state, int x) //得到与x所配对的左括号的位置
{ int cnt = 1, l = x; while (cnt) cnt += c[get(state, --l)]; return l; }
int getr(int state, int x) //得到与x所匹配的右括号的位置
{ int cnt = -1, r = x; while (cnt) cnt += c[get(state, ++r)]; return r; } void update(int x, int y, int state, LL val) {//状态转移(分类讨论), 刷表法
int p = get(state, y), q = get(state, y + 1);
if (mp[x][y] == '*') {//如果是障碍
if (p == 0 && q == 0) Ht[now ^ 1][state] += val;//特判
return;
} if (p == 0 && q == 0) {//如果没有插头
if (x == n - 1 || y == m - 1) return;
int newst = set(state, y, 1);
newst = set(newst, y + 1, 2);
Ht[now ^ 1][newst] += val;
return;
} if (p == 0 || q == 0) {//如果只有一端有插头,则往右或往下插
if (y < m - 1) {//往下插
int newst = set(state, y, 0);
newst = set(newst, y + 1, p + q);
Ht[now ^ 1][newst] += val;
}
if (x < n - 1) {//往右插
int newst = set(state, y, p + q);
newst = set(newst, y + 1, 0);
Ht[now ^ 1][newst] += val;
}
return;
} int newst = set(state, y, 0); newst = set(newst, y + 1, 0); if (p == 1 && q == 1) //如果两个插头同为左括号,连起来后y+1对应的右插头要变成左插头
newst = set(newst, getr(state, y + 1), 1);
else if (p == 2 && q == 2) //如果两个插头同为右括号,连起来后y对应的左插头要变成右插头
newst = set(newst, getl(state, y), 2);
else if (p == 1 && q == 2 && (x != ex || y != ey)) return;//只有最后一个格子才能转移 Ht[now ^ 1][newst] += val;
} int main() {
#ifndef ONLINE_JUDGE
freopen("BZOJ1814.in", "r", stdin);
#endif
cin >> n >> m;
for (int i = 0; i < n; ++ i) cin >> mp[i];
for (int i = 0; i < n; ++ i)
for (int j = 0; j < m; ++ j)
if (mp[i][j] == '.') ex = i, ey = j;
now = 0;
Ht[now].clear();
Ht[now][0] = 1;//别忘了
for (int i = 0; i < n; ++ i) {
//下面一部分是转移到下一行时的key<<=2
T.clear();
for (tr1::unordered_map<int, LL>::iterator it = Ht[now].begin(); it != Ht[now].end(); ++ it)
T[it->first<<2] = it->second;
swap(T, Ht[now]); for (int j = 0; j < m; ++ j) {
Ht[now ^ 1].clear();//记得转移之前清除
for (tr1::unordered_map<int, LL>::iterator it = Ht[now].begin(); it != Ht[now].end(); ++ it)
update(i, j, it->first, it->second);
now ^= 1;
}
}
cout << Ht[now][0] << endl;//最后的轮廓线状态就是0
}

手码Hash_Table:

#include <iostream>
#include <cstdio>
#include <cstring> using namespace std; const int maxM = 200005; #define LL long long char mp[20][20];
int c[4] = {0, -1, 1, 0};
int n, m, ex, ey; struct Hash_List {
struct Node {
int key, nxt;
LL val;
} data[maxM];
int head[maxM], cnt;
void init() { cnt = 0; memset(head, 0, sizeof head); }
void insert(int key, LL val) {
int x = key % maxM;
for (int i = head[x]; i; i = data[i].nxt)
if (data[i].key == key) {
data[i].val += val;
return;
}
data[++cnt] = (Node) { key, head[x], val };
head[x] = cnt;
}
LL getval(int key) {
int x = key % maxM;
for (int i = head[x]; i; i = data[i].nxt) {
if (data[i].key == key) {
return data[i].val;
}
}
return 0;
}
}DP[2]; int now;
int set(int state, int x, int val)
{ x <<= 1; return (state & (~(3<<x))) | (val << x); }
int get(int state, int x)
{ x <<= 1; return (state >> x) & 3; }
int getl(int state, int x)
{ int cnt = 1, l = x; while (cnt) cnt += c[get(state, --l)]; return l; }
int getr(int state, int x)
{ int cnt = -1, r = x; while (cnt) cnt += c[get(state, ++r)]; return r; } void update(int x, int y, int state, LL val) {
int p = get(state, y), q = get(state, y + 1);
if (mp[x][y] == '*') {
if (p == 0 && q == 0) DP[now ^ 1].insert(state, val);
return;
} if (p == 0 && q == 0) {
if (x == n - 1 || y == m - 1) return;
int newst = set(state, y, 1);
newst = set(newst, y + 1, 2);
DP[now ^ 1].insert(newst, val);
return;
} if (p == 0 || q == 0) {
if (y < m - 1) {
int newst = set(state, y, 0);
newst = set(newst, y + 1, p + q);
DP[now ^ 1].insert(newst, val);
}
if (x < n - 1) {
int newst = set(state, y, p + q);
newst = set(newst, y + 1, 0);
DP[now ^ 1].insert(newst, val);
}
return;
} int newst = set(state, y, 0); newst = set(newst, y + 1, 0); if (p == 1 && q == 1)
newst = set(newst, getr(state, y + 1), 1);
if (p == 2 && q == 2)
newst = set(newst, getl(state, y), 2);
if (p == 1 && q == 2 && (x != ex || y != ey)) return; DP[now ^ 1].insert(newst, val);
} int main() {
#ifndef ONLINE_JUDGE
freopen("BZOJ1814.in", "r", stdin);
#endif
cin >> n >> m;
for (int i = 0; i < n; ++ i) cin >> mp[i];
for (int i = 0; i < n; ++ i)
for (int j = 0; j < m; ++ j)
if (mp[i][j] == '.') ex = i, ey = j;
now = 0;
DP[now].init(); DP[now].insert(0, 1);
for (int i = 0; i < n; ++ i) {
for (int j = 1; j <= DP[now].cnt; ++ j) DP[now].data[j].key <<= 2;
for (int j = 0; j < m; ++ j) {
DP[now ^ 1].init();
for (int k = 1; k <= DP[now].cnt; ++ k)
update(i, j, DP[now].data[k].key, DP[now].data[k].val);
now ^= 1;
}
}
cout << DP[now].getval(0) << endl;
}

P5056 插头dp的更多相关文章

  1. P5056 【模板】插头dp

    \(\color{#0066ff}{ 题目描述 }\) 给出n*m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路.问有多少种铺法? \(\color{#0066ff}{输入格式}\) 第1 ...

  2. [学习笔记]插头dp

    基于连通性的状压dp 巧妙之处:插头已经可以表示内部所有状态了. 就是讨论麻烦一些. 简介 转移方法:逐格转移,分类讨论 记录状态方法:最小表示法(每次要重新编号,对于一类没用“回路路径”之类的题,可 ...

  3. 插头dp小结

    插头dp: \(A:\)插头dp是什么? \(B:\)一种基于连通性状态压缩的动态规划问题 \(A:\)请问有什么应用呢? \(B:\)各种网格覆盖问题,范围允许状压解决,常用于计算方案数与联通块权值 ...

  4. 插头 dp

    插头dp 洛谷 黑题板子? P5056 给出n×m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路.问有多少种铺法? 1.轮廓线 简单地说,轮廓线就是已决策格子和未决策格子的分界线: 2,插 ...

  5. P5056-[模板]插头dp

    正题 题目链接:https://www.luogu.com.cn/problem/P5056 题目大意 \(n*m\)的网格,求有多少条回路可以铺满整个棋盘. 解题思路 插头\(dp\)的,写法是按照 ...

  6. 插头dp

    插头dp 感受: 我觉得重点是理解,算法并不是直接想出怎样由一种方案变成另一种方案.而是方案本来就在那里,我们只是枚举状态统计了答案. 看看cdq的讲义什么的,一开始可能觉得状态很多,但其实灰常简单 ...

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

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

  8. HDU 4949 Light(插头dp、位运算)

    比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题.. 因为写完之后,无限TLE... 直到后来用位运算代替了我插头dp常用的decode.encode.shift三个函数以 ...

  9. 插头DP专题

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

随机推荐

  1. 运行Python

    安装好python环境,在Windows系统下运行cmd命令行,是windows提供的命令行模式. 在命令行下,可以执行python进入Python交互式环境,也可以执行python hello.py ...

  2. 【JAVA】学习笔记

    对程序员来说,学习一门新的语言,最开始的代码当然是hello world!下面我们从这段代码入手,一步一步来学习Java基础知识. class Hello{ public static void ma ...

  3. iOS | XIB简单应用和注意点

    2018开篇第一篇文章,本文分享一点关于XIB的小知识,对于iOS开发新人来说或许有用. XIB 是 Interface Builder 的图形界面设计文档. 从Xcode 3.0 开始,苹果提供Xi ...

  4. SQL Server中的三种Join方式

      1.测试数据准备 参考:Sql Server中的表访问方式Table Scan, Index Scan, Index Seek 这篇博客中的实验数据准备.这两篇博客使用了相同的实验数据. 2.SQ ...

  5. shell的命令格式

    参考高峻峰 著 循序渐进Linux(第二版) command [options] [arguments] command:表示命令的名称 options:表示命令的选项 arguments:表示命令的 ...

  6. java中的基本算法

    整理一下常用的又基础的算法.由于平时的项目比较简单,很少用到算法,但工作不只是眼前的苟且,还有诗和远方. 1.链表 链表用来存储数据,由一系列的结点组成.这些结点的物理地址不一定是连续的,即可能连续, ...

  7. 分布式日志系统ELK搭建

    ELK:Elasticsearch  Logstash Kibana Elasticsearch:是基于JSON的分布式搜索和分析引擎,专为实现水平扩展.高可用和管理便捷性而设计 Logstash:是 ...

  8. vue项目苹果微信端使用this.$router.go(-1)返回上一页,上一页并不会重新加载的问题

    window.addEventListener('pageshow', function(e) { // 通过persisted属性判断是否存在 BF Cache if (e.persisted) { ...

  9. 微信小程序引用iconfont图标字体解决方案;

    1)首先,登录阿里巴巴iconfont.cn 2)新建项目 3)点击icon收藏 4)加入到test项目中   5)下载到本地解压   6)生成代码   7)复制iconfont.css到xxx.wx ...

  10. visual studio 2015密钥

    Visual Studio Professional 2015简体中文版(专业版)KEY:HMGNV-WCYXV-X7G9W-YCX63-B98R2Visual Studio Enterprise 2 ...