[学习笔记]DP模型·路径长度之和
2017-12-30 13:59
302 查看
一、问题
给定一棵n个节点的无根带权树,要从中选出K个不同的点A1,A2,...,AK,最小化∑K−1i=1dist(Ai,Ai+1)的值。n≤3000,k≤n。dist(u,v)为树上u到v的距离。二、模型建立
可以把问题看作选出K个不同的点A1,A2,...,AK,然后从A1走到A2,再走到A3,…,最后走到AK的最小代价。把原图视为有根树,然后树形DP。由于要选出K个点,所以考虑树形背包DP,定义f[u][i]表示在u的子树内选出i个点的最小代价,但是这样是没有正确性的。因为将两个子树合并时,有可能不断地在这两个子树内来回走。所以DP模型改为:
f[u][i]:u的子树内选出i个点,第1个点和第i个点都为u的最小代价,也就是在u的子树内,从u开始,最后回到u。
g[u][i]:u的子树内选出i个点,第1个点为u的最小代价,也就是在u的子树内,从u开始,最后回到u的子树内的任一节点。
h[u][i]:u的子树内选出i个点,这i个点中存在一个点为u的最小代价,也就是在u的子树内,从任意节点开始,最后回到子树内的任意节点,但必须经过点u。
容易得出最后结果为minni=1h[i][K]。
三、转移
一开始时,f[u][1]=g[u][1]=h[u][1]=0。以下设当前枚举到了u的子节点v,f′[u][i]表示u的已经枚举过的子树的f[u][i],g′和h′同理。以下的图中,红色区域为u的已经枚举过的子树,黄色区域为v的子树。val(u,v)表示边(u,v)的权值。
f的转移
如下图,即从u开始,在红色区域走一圈后回到u,再到v,在黄色区域走一圈后又回到v,最后回到u,在这个路程中,边(u,v)被走了两次,所以转移为:f[u][i+j]=min(f[u][i+j],f′[u][i]+f[v][j]+val(u,v)∗2)
g的转移
转移一:终点在黄色区域。如下图,从u开始,在红色区域走一圈后回到u,再到v,最后回到黄色区域的任意节点。在这个路程中,边(u,v)被走了一次,所以转移为:g[u][i+j]=min(g[u][i+j],f′[u][i]+g[v][j]+val(u,v))
转移二:终点在红色区域。如下图,从u开始,先到v,在黄色区域里走一圈后回到v,再回到u,最后回到红色区域的任意节点。在这个路程中,边(u,v)被走了两次,所以转移为:
g[u][i+j]=min(g[u][i+j],g′[u][i]+f[v][j]+val(u,v)∗2)
h的转移
转移一:起点和终点一个在红色区域,一个在黄色区域。此时一定是从其中一个区域出发,到达u之后回到另一个区域内。在这个路程中,边(u,v)被走了一次,所以转移为:h[u][i+j]=min(h[u][i+j],g′[u][i]+g[v][j]+val(u,v))
转移二:起点和终点都在红色区域。也就是从红色区域的任意一点出发,到达u后走到v,在黄色区域走一圈后回到v,再走到u,最后回到红色区域内的任意节点。在这个路程中,边(u,v)被走了两次,所以转移为:
h[u][i+j]=min(h[u][i+j],h′[u][i]+f[v][j]+val(u,v)∗2)
转移三:起点和终点都在黄色区域。也就是从黄色区域的任意一点出发,到达v后走到u,在红色区域走一圈后回到u,再走到v,最后回到黄色区域内的任意节点。在这个路程中,边(u,v)被走了两次,所以转移为:
h[u][i+j]=min(h[u][i+j],f′[u][i]+h[v][j]+val(u,v)∗2)
实现细节
考虑到有可能黄色区域没有被经过。所以要首先令f[u][i]=f′[u][i],g[u][i]=g′[u][i],h[u][i]=h<
4000
span style="display: inline-block; width: 0px; height: 2.16em;">′[u][i]。
四、复杂度分析
看上去是O(n3)的,但是第二维i的上界只有u的子树大小,因此两层分别枚举两个区域的大小,相当于每一对点都只在lca处被计算了一次,所以复杂度为O(n2)。五、代码
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || /*orz mx & xmk*/ c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res; } const int N = 3005, M = 6005, INF = 0x3f3f3f3f; int n, K, ecnt, nxt[M], adj , go[M], f , g , h , sze , ans = 0x3f3f3f3f, val[M], x , y , z ; void chkmin(int &a, int b) {if (b < a) a = b;} void add_edge(int u, int v, int w) { nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; val[ecnt] = w; nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u; val[ecnt] = w; } void dfs(int u, int fu) { int i, j; sze[u] = 1; memset(f[u], INF, sizeof(f[u])); memset(g[u], INF, sizeof(g[u])); memset(h[u], INF, sizeof(h[u])); f[u][1] = g[u][1] = h[u][1] = 0; for (int e = adj[u], v; e; e = nxt[e]) { if ((v = go[e]) == fu) continue; dfs(v, u); for (i = 1; i <= sze[u] + sze[v]; i++) x[i] = f[u][i], y[i] = g[u][i], z[i] = h[u][i]; for (i = 1; i <= sze[u]; i++) for (j = 1; j <= sze[v]; j++) { chkmin(x[i + j], f[u][i] + (val[e] << 1) + f[v][j]); chkmin(y[i + j], f[u][i] + val[e] + g[v][j]); chkmin(y[i + j], (val[e] << 1) + f[v][j] + g[u][i]); chkmin(z[i + j], g[u][i] + val[e] + g[v][j]); chkmin(z[i + j], h[u][i] + (val[e] << 1) + f[v][j]); chkmin(z[i + j], h[v][j] + (val[e] << 1) + f[u][i]); } sze[u] += sze[v]; for (i = 1; i <= sze[u]; i++) f[u][i] = x[i], g[u][i] = y[i], h[u][i] = z[i]; } if (K <= sze[u]) chkmin(ans, h[u][K]); } int main() { int i, x, y, z; n = read(); K = read(); for (i = 1; i < n; i++) x = read(), y = read(), z = read(), add_edge(x, y, z); dfs(1, 0); cout << ans << endl; return 0; }
相关文章推荐
- 人工智障学习笔记——强化学习(2)基于模型的DP方法
- 微软CodeDom模型学习笔记(四)
- Hadoop学习笔记—4.初识MapReduce 一、神马是高大上的MapReduce MapReduce是Google的一项重要技术,它首先是一个编程模型,用以进行大数据量的计算。对于大数据
- C++对象模型 学习笔记01
- 最大熵学习笔记(三)最大熵模型
- XML学习1_xpath路径表达式笔记
- OpenCV学习笔记之八(保存视频,录制视频,cvLoadImage的路径)
- 模型思维_第1-4课_学习笔记
- android 根据uri获取路径及图片压缩、旋转的学习笔记
- 视觉词袋模型BOW学习笔记及matlab编程实现
- 数据库学习笔记:实体联系模型
- 大前端学习笔记整理【二】CSS视觉格式化模型
- Java学习笔记——创建文件路径
- Silverlight 学习笔记——应用程序模型
- [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计
- FreeBSD学习笔记03-默认搜索路径
- 前端学习笔记--CSS--元素类型、布局模型
- 树形dp学习笔记
- 最大熵学习笔记(三)最大熵模型
- Thrift学习笔记(3)--Thrift 多线程阻塞式IO服务模型