洛谷 P5056 【模板】插头dp
题目链接
题意
给出n*m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路。问有多少种铺法?
思路
比赛时基本做不出来,就学个新算法玩玩。
学习链接
代码对于我这个不会hash_table 的不太友好,先自己封装了一个用着舒服的hash_table,当然也可以直接用STL里的 unordered_map
,初学算法我认为直接使用后者更好,循序渐进。
插头dp简单的说还是轮廓线的状压dp?,多考虑了一种连通性问题。
用括号表示法表示轮廓线后,然后考虑状态转移。
枚举每点,考虑左边的朝右插头 r
,上边朝下插头 d
,左插头1表示,右插头2表示
- if 当前点是障碍
- else if (!r && !d)
- else if (r && !d)
- else if (!r && d)
- else if (r == 1 && d == 1)
- else if (r == 2 && d == 2)
- else if (r == 1 && d == 2)
- else if (r == 2 && d == 1)
所有的情况就这么多,然后每点考虑插头形状转移即可
一个坑点 | ^
运算符优先级不同,不是从左到右运算,然后找了半天bug,还是用 + -
比较稳。
代码
STL unordered_map
代码
991ms
吸氧后 228ms
#include <bits/stdc++.h>
using namespace std;#define ll long longunordered_map<ll,ll> dp[3];
// chatou 0 null, 1 right, 2 down
ll n, m, endx, endy, a[15][15], bit[15];
#define prel (1ll<<bit[j-1])
#define prer (1ll<<bit[j])void solve() {ll cur = 0, ans = 0;dp[cur].clear();dp[0][0] = 1;for(ll i = 1; i <= n; ++i) {dp[2].clear();for(auto j : dp[cur]) dp[2][j.first<<2] = j.second;dp[cur] = dp[2];for(ll j = 1; j <= m; ++j) {cur ^= 1;dp[cur].clear();for(auto k : dp[cur^1]) {ll sta = k.first;ll w = k.second;ll d = (sta>>bit[j])&3ll;ll r = (sta>>bit[j-1])&3ll;
// printf("%lld %lld - %lld %lld\n",i,j,sta,w);
// printf("%lld = %lld\n\n",r,d);if(!a[i][j]) {if(!r && !d) dp[cur][sta] += w;}else if(!r && !d) {if(a[i+1][j] && a[i][j+1]) dp[cur][sta + prel + (2*prer)] += w;}else if(r && !d) {if(a[i+1][j]) dp[cur][sta] += w;if(a[i][j+1]) dp[cur][sta - (r*prel) + (r*prer)] += w;}else if(!r && d) {if(a[i+1][j]) dp[cur][sta + (d*prel) - (d*prer)] += w;if(a[i][j+1]) dp[cur][sta] += w;}else if(r == 1 && d == 1) {ll cnt = 1;for(ll p = j+1; p <= m; ++p) {if(((sta>>bit[p])&3ll) == 1) ++cnt;if(((sta>>bit[p])&3ll) == 2) --cnt;if(!cnt) {dp[cur][(sta - (r*prel) - (d*prer)) - (1<<bit[p])] += w;break;}}}else if(r == 2 && d == 2) {ll cnt = 1;for(ll p = j-2; p >= 0; --p) {if(((sta>>bit[p])&3ll) == 1) --cnt;if(((sta>>bit[p])&3ll) == 2) ++cnt;if(!cnt) {dp[cur][(sta - (r*prel) - (d*prer)) + (1<<bit[p])] += w;break;}}}else if(r == 2 && d == 1) {dp[cur][sta - (r*prel) - (d*prer)] += w;}else if(r == 1 && d == 2) { // okif(i == endx && j == endy) ans += w;}}}}printf("%lld\n",ans);
}int main() {scanf("%lld%lld",&n,&m);for(ll i = 1; i <= n; ++i) {char s[15];scanf("%s",s+1);for(ll j = 1; j <= m; ++j) {if(s[j] == '.') {a[i][j] = 1;endx = i;endy = j;}}}for(ll i = 1; i <= 13; ++i) bit[i] = i<<1;solve();return 0;
}
手写hash_table
代码
577ms
吸氧后 562ms
#include <bits/stdc++.h>
using namespace std;#define ll long longstruct hash_table {ll hash_mod = 590027;ll state[600000], ans[600000], up;ll tot, first[600000], nxt[600000], w[600000];void init() {memset(first, 0, sizeof(first));tot = 0;up = 0;}ll ins(ll sta, ll val) {ll key = sta%hash_mod;for(ll i = first[key]; i; i = nxt[i]) {if(state[w[i]] == sta) return ans[w[i]] += val;}state[++up] = sta;ans[up] = val;nxt[++tot] = first[key];w[tot] = up;first[key] = tot;return val;}
}dp[2];/*hash_table*/
// chatou 0 null, 1 right, 2 down
ll n, m, endx, endy, a[15][15], bit[15];
#define prel (1ll<<bit[j-1])
#define prer (1ll<<bit[j])void solve() {ll cur = 0, ans = 0;dp[cur].init();dp[0].ins(0,1);for(ll i = 1; i <= n; ++i) {for(ll j = 1; j <= dp[cur].up; ++j) dp[cur].state[j] <<= 2;for(ll j = 1; j <= m; ++j) {cur ^= 1;dp[cur].init();for(ll k = 1; k <= dp[cur^1].up; ++k) {ll sta = dp[cur^1].state[k];ll w = dp[cur^1].ans[k];ll d = (sta>>bit[j])&3ll;ll r = (sta>>bit[j-1])&3ll;
// printf("%lld %lld - %lld %lld\n",i,j,sta,w);
// printf("%lld = %lld\n\n",r,d);if(!a[i][j]) {if(!r && !d) dp[cur].ins(sta,w);}else if(!r && !d) {if(a[i+1][j] && a[i][j+1]) dp[cur].ins(sta + prel + (2*prer),w);}else if(r && !d) {if(a[i+1][j]) dp[cur].ins(sta,w);if(a[i][j+1]) dp[cur].ins(sta - (r*prel) + (r*prer),w);}else if(!r && d) {if(a[i+1][j]) dp[cur].ins(sta + (d*prel) - (d*prer),w);if(a[i][j+1]) dp[cur].ins(sta,w);}else if(r == 1 && d == 1) {ll cnt = 1;for(ll p = j+1; p <= m; ++p) {if(((sta>>bit[p])&3ll) == 1) ++cnt;if(((sta>>bit[p])&3ll) == 2) --cnt;if(!cnt) {dp[cur].ins((sta - (r*prel) - (d*prer)) - (1<<bit[p]),w);break;}}}else if(r == 2 && d == 2) {ll cnt = 1;for(ll p = j-2; p >= 0; --p) {if(((sta>>bit[p])&3ll) == 1) --cnt;if(((sta>>bit[p])&3ll) == 2) ++cnt;if(!cnt) {dp[cur].ins((sta - (r*prel) - (d*prer)) + (1<<bit[p]),w);break;}}}else if(r == 2 && d == 1) {dp[cur].ins(sta - (r*prel) - (d*prer),w);}else if(r == 1 && d == 2) { // okif(i == endx && j == endy) ans += w;}}}}printf("%lld\n",ans);
}int main() {scanf("%lld%lld",&n,&m);for(ll i = 1; i <= n; ++i) {char s[15];scanf("%s",s+1);for(ll j = 1; j <= m; ++j) {if(s[j] == '.') {a[i][j] = 1;endx = i;endy = j;}}}for(ll i = 1; i <= 13; ++i) bit[i] = i<<1;solve();return 0;
}
洛谷 P5056 【模板】插头dp相关推荐
- 洛谷--橙色百道DP总结
最近刷完了洛谷橙色DP大约一百道,算是发现了一些套路,就部分题目做一些总结. 大概分为三类 第一类,九大背包及其衍生 第二类,经典DP模型,如LCS,LIS等 第三类,实际问题背景的普通,环形,树上D ...
- Educational Codeforces Round 81 (Rated for Div. 2) F.Good Contest \ 洛谷 划艇 组合 计数dp
cf传送门 P3643 [APIO2016]划艇 文章目录 题意: 思路: 题意: aia_iai在[li,ri][l_i,r_i][li,ri]等概率随机选一个数,求aaa数组不增的概率. 思 ...
- 洛谷P1108 低价购买[DP | LIS方案数]
题目描述 "低价购买"这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:"低价购买:再低价购买".每次你购买一支股 ...
- 洛谷P1244 青蛙过河 DP/思路
又是一道奇奇怪怪的DP(其实是思路题). 原文戳>>https://www.luogu.org/problem/show?pid=1244<< 这题的意思给的挺模糊,需要一定的 ...
- 洛谷 P2657 (数位DP)
### 洛谷 P2657 题目链接 ### 题目大意:给你一个数的范围 [A,B] ,问你这段区间内,有几个数满足如下条件: 1.两个相邻数位上的数的差值至少为 2 . 2.不包含前导零. 很简单的数 ...
- 洛谷 Golden Sword(dp,优先队列优化【含板子】)|| 补充练习:洛谷 跳房子
题目链接: 「SWTR-03」Golden Sword - 洛谷 思路: 设表示放第i个原料,锅里共有 j 个时的耐久度之和. 容易知道dp方程为,其中 这样就可以写出暴力dp的代码如下:(需要枚举i ...
- 专题·树链剖分【including 洛谷·【模板】树链剖分
初见安~~~终于学会了树剖~~~ [兴奋]当初机房的大佬在学树剖的时候我反复强调过:"学树剖没有前途的!!!" 恩.真香. 一.重链与重儿子 所谓树剖--树链剖分,就是赋予一个链的 ...
- 洛谷·【模板】点分树 | 震波【including 点分树
初见安-这里是传送门:洛谷P6329 [模板]点分树 | 震波 一.点分树 其实你会点分治的话,点分树就是把点分治时的重心提出来重新连城一棵树. 比如当前点是u,求出子树v的重心root后将root与 ...
- 【洛谷P4719】动态DP【LCT】【矩阵】
之前的后缀平衡树其实没完,只是过于鬼畜就弃了 传送门 题意:带修改点权的最大独立集 N≤1e5N \leq 1e5N≤1e5 一个没啥用的模板,不过适合练习LCT 先写出方程 f(u,0)=∑v∈so ...
- 强连通分量:洛谷P3387 模板:缩点
传送门 顾名思义,模板awa #include <cstdio> #include <cstring> #include <cmath> #include < ...
最新文章
- BPDU tunnel技术简介
- Swift可选绑定、断言
- JavaScript学习备忘
- GitHub 2017 年度报告,最受欢迎的编程语言是?
- C#基础系列 - 抽象类及其方法的学习
- 并发事务正确性的准则 可串行化_从0到1理解数据库事务(上):并发问题与隔离级别...
- 【转】C++/CLI入门系列 第二篇:封装C++ dll库,提供接口给C#调用
- oracle 分页_80分页查询,不止写法
- mysql建用户之后取消drop库权限
- Windows 下 PHP 开发环境配置系列四 - IIS+php+mysql
- android sqlite 数据库中使用的类型
- mysql_fetch_row()获取显示数据
- 【论文翻译笔记】A Systematic Evaluation of StaticAPI-Misuse Detectors
- mysql 数据库索引命名规范_MYSQL数据库命名及设计规范
- ofd文件转化成pdf的免费方法
- 单词语音音标正则式查询分析JavaScript应用
- SQL编程和高级查询
- Mac电脑的文件快捷访问工具:Default Folder X 5
- 如何绕过强制门户——克隆 MAC 地址
- 银联支付、支付宝支付和微信支付有什么优势?