Ural 1519. Formula 1 ------ 插头dp
2015-09-13 02:06
483 查看
题目链接
学习插头dp差不多也有段时间了, 最开始水的一道题是Eat the tree, 多回路类型的插头dp。那时候看了cdq的《基于连通性状态压缩的动态规划问题》以及各路大神的blog, 然而对于插头dp仍是一头雾水, 虽然对于大神们来说插头dp还是挺水的, 但是我还是花了很长时间才最终看懂了那些位运算代表的含义。
这道题正好是cdq论文中的例题, 方法在论文中也说得比较明确了, 这里我来说说我对于括号表示法的理解。首先, 我们的动态规划是一行一行来的, dp[i][j] 的下一个格子为 dp[i][j + 1], 而dp[i][m] 的下一个格子为 dp[i + 1][1] 每个格子的每个状态都记录着与轮廓线有共线的格子的边的插头状态 (我自己也觉得这句话有点绕, 语文不太好 = =) 差不多是下面这种样子 :
这里当前格子为(3, 2),而插头状态为 11101(用1表示有插头, 0表示没插头)
而对于(3,2)这一个格子,我们另外用两个值left 和 up表示这个格子左边和上边是否有通向它的插头。这里left = 1, up = 0。
剩下要做的就是状态转移了。这里中要注意的是因为只能有一个回路,而在括号法中当left=1, up=2的插头连接时会形成回路, 所以这种情况只能出现在最后一个无障碍的格子中。
还有一个要注意的地方是当相同方向的括号连接时, 要注意改变附近的某个插头的括号方向, 具体见下图:
其中红色为论文中的左括号, 而蓝色为右括号, 很显然当有相同颜色的插头连接时, 我们要改变附近某个插头的颜色。
下面是我的代码:
学习插头dp差不多也有段时间了, 最开始水的一道题是Eat the tree, 多回路类型的插头dp。那时候看了cdq的《基于连通性状态压缩的动态规划问题》以及各路大神的blog, 然而对于插头dp仍是一头雾水, 虽然对于大神们来说插头dp还是挺水的, 但是我还是花了很长时间才最终看懂了那些位运算代表的含义。
这道题正好是cdq论文中的例题, 方法在论文中也说得比较明确了, 这里我来说说我对于括号表示法的理解。首先, 我们的动态规划是一行一行来的, dp[i][j] 的下一个格子为 dp[i][j + 1], 而dp[i][m] 的下一个格子为 dp[i + 1][1] 每个格子的每个状态都记录着与轮廓线有共线的格子的边的插头状态 (我自己也觉得这句话有点绕, 语文不太好 = =) 差不多是下面这种样子 :
这里当前格子为(3, 2),而插头状态为 11101(用1表示有插头, 0表示没插头)
而对于(3,2)这一个格子,我们另外用两个值left 和 up表示这个格子左边和上边是否有通向它的插头。这里left = 1, up = 0。
剩下要做的就是状态转移了。这里中要注意的是因为只能有一个回路,而在括号法中当left=1, up=2的插头连接时会形成回路, 所以这种情况只能出现在最后一个无障碍的格子中。
还有一个要注意的地方是当相同方向的括号连接时, 要注意改变附近的某个插头的括号方向, 具体见下图:
其中红色为论文中的左括号, 而蓝色为右括号, 很显然当有相同颜色的插头连接时, 我们要改变附近某个插头的颜色。
下面是我的代码:
#include <bits/stdc++.h> #define update(a, b) (a) += (b) using namespace std; const int HASH = 10007; const int STATE = 1000010; struct HASHMAP { int head[HASH], state[STATE], nxt[STATE], num; long long f[STATE]; void init() { num = 0; memset(head, -1, sizeof head); } void push(int st, long long ans) { int h = st % HASH; for (int i = head[h]; ~ i; i = nxt[i]) { if (st == state[i]) { f[i] += ans; return; } } state[num] = st; nxt[num] = head[h]; f[num] = ans; head[h] = num++; } } dp[2]; int n, m; int a[15][15]; int ex, ey; void init() { char s[20]; scanf("%d %d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%s", s); for (int j = 1; j <= m; j++) { a[i][j] = s[j - 1] == '.'; if (a[i][j]) ex = i, ey = j; } } } int get(int st, int pos) { return st >> (pos << 1) & 3; } int change(int st, int pos, int w) { st ^= get(st, pos) << (pos << 1); st ^= w << (pos << 1); return st; } long long plugdp() { HASHMAP *now = dp, *pre = dp + 1; now->init(); now->push(0, 1); for (int i = 1; i <= n; i++) { for (int k = 0; k < now->num; k++) now->state[k] <<= 2; for (int j = 1; j <= m; j++) { swap(now, pre); now->init(); for (int k = 0; k < pre->num; k++) { int st = pre->state[k]; long long add = pre->f[k]; int left = get(st, j - 1); int up = get(st, j); if (!a[i][j]) { now->push(change(change(st, j - 1, 0), j, 0), add); continue; } if (left && up) { int nst = change(change(st, j - 1, 0), j, 0); if (left == 1 && up == 2) { if (i == ex && j == ey) now->push(nst, add); } else { if (left == up) { int cnt = 0; for (int idx = left == 1 ? j : j - 1; idx <= m && idx >= 0; left == 1 ? idx++ : idx--) { int t = get(st, idx); if (t == 1) cnt++; if (t == 2) cnt--; if (!cnt) { nst = change(nst, idx, left); break; } } } now->push(nst, add); } } else if (left || up) { int w = left | up; if (a[i][j + 1]) now->push(change(change(st, j - 1, 0), j, w), add); if (a[i + 1][j]) now->push(change(change(st, j - 1, w), j, 0), add); } else { if (a[i][j + 1] && a[i + 1][j]) now->push(change(change(st, j - 1, 1), j, 2), add); } } } } long long ans = 0; for (int i = 0; i < now->num; i++) ans += now->f[i]; return ans; } int main() { init(); printf("%lld\n", plugdp()); }
相关文章推荐
- 使用位运算实现网页中的过滤、筛选功能实例
- C#使用DeflateStream解压缩数据文件的方法
- C#调用WinRar执行rar、zip压缩的方法
- C#实现页面GZip或Deflate压缩的方法
- C#使用iCSharpcode进行文件压缩实现方法
- C#枚举中的位运算权限分配浅谈
- C#实现压缩HTML代码的方法
- Asp.net在线备份、压缩和修复Access数据库示例代码
- 使用UglifyJS合并/压缩JavaScript的方法
- 高性能WEB开发 JS、CSS的合并、压缩、缓存管理
- 脚本分析、压缩、混淆工具 JSA新版本发布,压缩效率提高大约10%
- 发布一个高效的JavaScript分析、压缩工具 JavaScript Analyser
- PHP实现图片压缩的两则实例
- shell 基本计算、逻辑运算、位运算详解
- 在IIS上启用Gzip压缩 (HTTP压缩)第1/3页
- javascript实现的样式表(CSS) 格式整理与压缩
- php zlib压缩和解压缩swf文件的代码
- YUI Compressor压缩JavaScript原理及微优化
- Java位运算和逻辑运算的区别实例
- Nginx中的Gzip压缩配置介绍