题面

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. SyncUI跨设备同步

    SynUI控制代码 <script type="text/javascript"> /* SyncUI script (Learn more at http://syn ...

  2. ArrayList使用

    package com.nrxt; import java.util.ArrayList; /** * 概述: * 功能: * 作者:郑肖亚 * 创建时间:2019/3/13 22:01 */ pub ...

  3. .net 导出Excel插件Npoi的使用

    1.NuGet搜索Npoi并安装 2.添加引用将包引用进来 3.Controller里引用 4.使用 public ActionResult ExportExcel() { plist = 数据源 H ...

  4. vue.esm.js:578 [Vue warn]: Missing required prop

    问题: 解决: required: true,属性是,这个必须填写

  5. 『ACM C++』PTA浙大 | 基础题 - 打印沙漏

    <数据结构>开课前的一些小作业练习,可能因为一个寒假都没有打C++手生了,整个寒假都在帮拍电影做后期特效,导致这道题居然用了两个钟去AC,深感惭愧,作个标记吧,下面上题. 一首好曲推荐:同 ...

  6. 3930: [CQOI2015]选数

    Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1958  Solved: 979[Submit][Status][Discuss] Descripti ...

  7. 【杂题总汇】AGC027 C - ABland Yard

    ◆AGC027◆C - ABland Yard 终于知道为什么比赛的时候这么多人做C题了…… +传送门+(这是beta版的) ◇ 题目(自己翻译的,不要在意细节……) P.S. (@ 2018-9-2 ...

  8. 全盘解决eclipse之maven项目报错

    每次新建maven的web(war包方式)项目时都会报错而且都要手动改,很麻烦 解决:(注意里面的jdk版本换成自己的) 改变maven配置文件   settings.xml 在文件的<prof ...

  9. javascript--事件对象e的来源、意义、应用及其属性的用法 function(e){}

    在类似于arcgis api for javascript中,经常会遇到function(e),以前一直不懂e是个什么玩意,这种写法啥意思,经过最近一段时间学习,对e有了很深了解,本文通过各种示例,由 ...

  10. MySQL单表数据查询(DQL)

    数据准备工作: CREATE TABLE student( sid INT PRIMARY KEY AUTO_INCREMENT, sname ), age TINYINT, city ), scor ...