[日常训练] Tree
来源:互联网 发布:淘宝手机端优惠券设置 编辑:程序博客网 时间:2024/06/08 00:39
分析 树形DP
经典的模型依旧只会暴力,果然蒟蒻呀- 设
f[u][j] 表示从点u 出发,在u 的子树中经过j 个点最后回到点u 的最小距离和 - 设
g[u][j] 表示从点u 出发,在u 的子树中经过j 个点最后停在任意一点(其实也相当于从u 的子树中任意一点出发,经过j 个点最后回到点u )的最小距离和 - 设
h[u][j] 表示在u 的子树中从任意一点出发,经过j 个点并保证经过点u ,最后停在任意一点的最小距离和 - 显然
f,g,h 都是由u 的子节点v 转移过来,则我们可以得到如下转移(为了描述方便,设已经处理完的u 的子节点的子树集合为A ,当前处理的子节点v 的子树为B ,用→ 表示每种转移所对应的在树上走的方案) - 对于
f[u][j] :f′[u][j+k]=min(f[v][k]+f[u][j]+2⋅dis(u,v))(u→A→u→B→u)
- 对于
g[u][j] :g′[u][j+k]=min(g[v][k]+f[u][j]+dis(u,v))(u→A→u→B) g′[u][j+k]=min(f[v][k]+g[u][j]+2⋅dis(u,v))(u→B→u→A)
- 对于
h[u][j] :h′[u][j+k]=min(f[v][k]+h[u][j]+2⋅dis(u,v))(A→u→B→u→A) h′[u][j+k]=min(h[v][k]+f[u][j]+2⋅dis(u,v))(B→u→A→u→B) h′[u][j+k]=min(g[v][k]+g[u][j]+dis(u,v))(A→u→B)
- 时间复杂度的证明也是比较经典了,每次枚举的是
szeu⋅szev ,相当于每次从A,B 中各任选一点,它们的LCA 为u ,这样的点对枚举不会重复,因此总的时间复杂度为O(n2)
代码
#include <iostream>#include <cstdio>#include <cctype>#include <algorithm>#include <cstring>using namespace std;namespace INOUT{ const int S = 1 << 20; char frd[S], *hed = frd + S; const char *tal = hed; inline char nxtChar() { if (hed == tal) fread(frd, 1, S, stdin), hed = frd; return *hed++; } inline int get() { char ch; int res = 0; bool flag = false; while (!isdigit(ch = nxtChar()) && ch != '-'); (ch == '-' ? flag = true : res = ch ^ 48); while (isdigit(ch = nxtChar())) res = res * 10 + ch - 48; return flag ? -res : res; }};using namespace INOUT;const int Maxn = 0x3f3f3f3f;const int N = 3005;int n, Ans = Maxn, K, sze[N];int f[N][N], g[N][N], h[N][N];int ff[N][N], gg[N][N], hh[N][N];struct Edge{ int to, cst; Edge *nxt;}p[N << 1], *T = p, *lst[N];inline void LinkEdge(int x, int y, int z){ (++T)->nxt = lst[x]; lst[x] = T; T->to = y; T->cst = z; (++T)->nxt = lst[y]; lst[y] = T; T->to = x; T->cst = z;}inline int Min(int x, int y) {return x < y ? x : y;}inline void CkMin(int &x, int y) {if (x > y) x = y;}inline void Dfs(int u, int fa){ sze[u] = 1; h[u][1] = g[u][1] = f[u][1] = 0; for (Edge *e = lst[u]; e; e = e->nxt) { int v = e->to; if (v == fa) continue; Dfs(v, u); for (int j = 1, jm = sze[u] + sze[v]; j <= jm; ++j) { ff[u][j] = f[u][j]; gg[u][j] = g[u][j]; hh[u][j] = h[u][j]; } int L1 = e->cst, L2 = e->cst << 1; for (int j = 1; j <= sze[u]; ++j) for (int k = 1; k <= sze[v]; ++k) { CkMin(ff[u][j + k], f[v][k] + f[u][j] + L2); CkMin(gg[u][j + k], g[v][k] + f[u][j] + L1); CkMin(gg[u][j + k], f[v][k] + g[u][j] + L2); CkMin(hh[u][j + k], f[v][k] + h[u][j] + L2); CkMin(hh[u][j + k], h[v][k] + f[u][j] + L2); CkMin(hh[u][j + k], g[v][k] + g[u][j] + L1); } for (int j = 1, jm = sze[u] + sze[v]; j <= jm; ++j) { f[u][j] = ff[u][j]; g[u][j] = gg[u][j]; h[u][j] = hh[u][j]; } sze[u] += sze[v]; } CkMin(Ans, h[u][K]);}int main(){ freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); n = get(); K = get(); int x, y; for (int i = 1; i < n; ++i) { x = get(); y = get(); LinkEdge(x, y, get()); } memset(f, Maxn, sizeof(f)); memset(g, Maxn, sizeof(g)); memset(h, Maxn, sizeof(h)); Dfs(1, 0); printf("%d\n", Ans); fclose(stdin); fclose(stdout); return 0;}
阅读全文
1 0
- [日常训练] Tree
- HEU日常训练10.02
- 日常训练小结
- 日常训练20161012 道路网
- 日常训练20161012 醉酒
- 日常训练20161014 跟踪
- 日常训练20161018 证据
- 日常训练20161018 subset
- 日常训练 平均数
- 日常训练 水箱
- 日常训练 棋盘游走
- 日常训练 20170531 数字
- 日常训练 20170531 探险
- 日常训练 20170531 矩阵
- 日常训练 20170602 Book
- 日常训练 20170602 Equation
- 日常训练 20170603 棋盘
- 日常训练 20170605 EasyProblem
- 85. Maximal Rectangle
- 文件泄露漏洞
- docker
- yii2 数据库事务
- 在tensorflow中使用函数封装操作的误区
- [日常训练] Tree
- FastDFS+Nginx实现文件服务器
- Python 全局变量 局部变量
- app 安装显示风险软件
- Roman to Integer 罗马数字转化成整数
- 遗传算法的基本原理和matlab实现
- vim 编辑python的一些设置
- Labview-运行崩溃,报错AccessViolation
- (二十)线程