插头dp
来源:互联网 发布:去除视频马赛克软件 编辑:程序博客网 时间:2024/05/17 03:49
插头DP小结?
因为独立插头还有最小表示法没有打过,独立插头没看懂,广义路径连看都没看过,所以这些不再本文的总结范围内。
因为独立插头还有最小表示法没有打过,独立插头没看懂,广义路径连看都没看过,所以这些不再本文的总结范围内。
去年学插头DP的时候还是很惧怕的,也只做了一题,还是按着课件对着标程打的。还好今年终于懂得原理了。其实打多了也变成模板了(当然每题的转移不一样)。
插头DP有下面的分类:
按模型:多回路问题、单回路问题、简单路径问题、广义路径问题
按表示方法:是否有插头、括号法(广义括号法)、最小表示法
插头DP最朴素的实现就是用f[i][j][k]记下在(i,?j)这个点轮廓线状态为k的答案。空间上很大,所以一般用队列实现了。而且队列实现可以免去动规数组初始化的麻烦。队列实现需要一个hash,对于内存比较宽裕的题目,可以直接开一个桶解决.
参考资料
基于连通性状态压缩的动态规划问题?- 陈丹琦
多回路问题
这类问题是最水的,只要记录当前位置有没有插头即可。比如说hdu1693。
有上插头和左插头→没有右插头或下插头
没有上插头或做插头→有右插头和下插头
只有一个插头→右插头和下插头分别只有一个
单回路问题
这类问题得维护连通性使得只存在一个联通快。具体的做法课件上讲的很清楚。例题有:ural1519?Formula?1poj1739 (如果在外面加一圈障碍的话,就变成上面那题了)
bzoj1187(这题允许任意起点,并且不要求遍历全图)
限制起点终点的简单路径问题
简单路径问题按理来说应该用独立插头来解决,但是这类问题因为限制了起点和终点,所以比较好解决,只要对每个格子的类型进行判断,根据不同的格子进行不同的转移即可。比如说:poj3133(这题网上都说是独立插头,但是直接特判格子就可以过掉了)
poj1739(这题如果不加一圈的话,用特判的方法还是很好写的)
#include <bits/stdc++.h>//http://www.lydsy.com/JudgeOnline/problem.php?id=1187#define maxn 110using namespace std;typedef long long ll;int n, m;int a[maxn][maxn];ll ans = -1ll << 60;#define M 2000010#define mod 997 struct Hashmap{ ll st[M]; int h[1000], size, nxt[M]; ll f[M]; void clear(){memset(h, 0, sizeof h); size = 0;} void push(ll hash_, ll val){ int tmp = hash_ % mod; for(int i = h[tmp]; i; i = nxt[i]){ if(st[i] == hash_){ f[i] = max(f[i], val); return; } } int now = ++ size; f[now] = val; st[now] = hash_; nxt[now] = h[tmp]; h[tmp] = now; }}dp[2]; int cur, code[20], ch[20]; void Decode(ll st){ for(int i = m; i >= 0; i --) code[i] = st & 7, st >>= 3;} ll Encode(){ ll ret = 0; memset(ch, -1, sizeof ch); ch[0] = 0; int cnt = 0; for(int i = 0; i <= m; i ++){ if(ch[code[i]] == -1)ch[code[i]] = ++ cnt; code[i] = ch[code[i]]; ret = ret << 3 | code[i]; } return ret;} void Shift(){ for(int i = m; i >= 1; i --) code[i] = code[i-1]; code[0] = 0;} inline void Change(int u, int v){ for(int i = 0; i <= m; i ++) if(code[i] == v) code[i] = u;} void DP(int i, int j){ dp[cur^1].clear(); for(int k = 1; k <= dp[cur].size; k ++){ Decode(dp[cur].st[k]); if(j == 1){if(code[m])continue;Shift();} int Left = code[j-1], Up = code[j]; if(Left && Up){ code[j] = code[j-1] = 0; if(Left == Up){ ll ENCODE = Encode(); if(ENCODE == 0)ans = max(ans, dp[cur].f[k] + a[i][j]); } else{ Change(Left, Up); dp[cur^1].push(Encode(), dp[cur].f[k] + a[i][j]); } } else if(Left || Up){ int tmp = Left ? Left : Up; code[j-1] = 0, code[j] = tmp; dp[cur^1].push(Encode(), dp[cur].f[k] + a[i][j]); code[j] = 0, code[j-1] = tmp; dp[cur^1].push(Encode(), dp[cur].f[k] + a[i][j]); } else{ dp[cur^1].push(Encode(), dp[cur].f[k]); code[j] = code[j-1] = 8; dp[cur^1].push(Encode(), dp[cur].f[k] + a[i][j]); } } cur ^= 1;} int main(){#ifndef ONLINE_JUDGE freopen("park.in","r",stdin); freopen("park.out","w",stdout);#endif scanf("%d%d", &n, &m); for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) scanf("%d", &a[i][j]); dp[cur].clear(); dp[cur].push(0, 0); for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) DP(i, j); printf("%lld\n", ans); return 0;}
阅读全文
1 0
- 插头DP
- 插头dp
- 插头dp
- 插头dp
- 插头DP
- 插头dp
- hdu 1693 插头dp
- 插头DP【入门】
- hdu 4064 (插头DP)
- poj 3133 插头Dp
- HDU-1693-插头dp
- POJ-1739-插头dp
- 插头DP(HDOJ1693)初识
- 【Learning】适妞来学 插头 dp
- tongji 30029 插头dp
- Hdu 1693 插头dp
- ZOJ 3466 插头dp
- 插头dp--hdu1639
- 嵌入式软件异步编程:异步带来的性能提升
- Matlab曲面拟合和插值
- 反射+类加载器
- USB设备驱动分析
- 算法提高 周期字串
- 插头dp
- c++中的左值与右值
- BZOJ2300: [HAOI2011]防线修建
- Tarjan的东西
- spring中bean的初始化过程
- 17、vue.js 之路由里的返回、前进、跳转
- net start mongodb 服务名无效解决方案
- InitInstance函数
- MFC Icon使用例子