题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=4987

题解

一道还不错的题咯。

很容易发现一个结论:这 \(k\) 个点构成的一定是一个连通块,并且走的时候应该是按照某种类似于 dfs 的遍历方式连续走的。

可以发现,最终答案应该有:从根的某个子树走出来,到某个子树中去的这样的情况,也有可能是从根到某个子树中去的情况;同时,过程中会用到从根到子树中走一遍再回到根的情况。这三种情况都需要考虑。

于是进行树形 dp,令 \(dp[x][i][0/1/2]\) 表示以 \(x\) 为根的子树中,选择了 \(i\) 个点,情况为从根到子树中走一遍再回到根/从根到某个子树中去(等同于从某个子树到根)/从根的某个子树走出来,到某个子树中去这三种情况,转移的时候,第二维直接背包合并,第三维是这样的:\(0+0\to 0, 0+1\to 1, 1+0\to 1, 0+2\to 2,1+1\to 2,2+0\to 2\)。


代码如下,时间复杂度为一般的背包合并 \(O(nk)\)。

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;} typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii; template<typename I> inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
} const int N = 3000 + 7;
const int INF = 0x3f3f3f3f; int n, m, ans;
int dp[N][N][3], siz[N]; struct Edge { int to, ne, w; } g[N << 1]; int head[N], tot;
inline void addedge(int x, int y, int z) { g[++tot].to = y, g[tot].w = z, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y, int z) { addedge(x, y, z), addedge(y, x, z); } inline void dfs(int x, int fa = 0) {
dp[x][1][0] = dp[x][1][1] = 0;
siz[x] = 1;
for fec(i, x, y) if (y != fa) {
dfs(y, x);
int w = g[i].w;
for (int i = std::min(m, siz[x]); i; --i)
for (int j = 1; j <= std::min(m, siz[y]); ++j) {
smin(dp[x][i + j][0], dp[x][i][0] + dp[y][j][0] + w * 2);
smin(dp[x][i + j][1], dp[x][i][0] + dp[y][j][1] + w);
smin(dp[x][i + j][1], dp[x][i][1] + dp[y][j][0] + w * 2);
smin(dp[x][i + j][2], dp[x][i][0] + dp[y][j][2] + w * 2);
smin(dp[x][i + j][2], dp[x][i][1] + dp[y][j][1] + w);
smin(dp[x][i + j][2], dp[x][i][2] + dp[y][j][0] + w * 2);
}
siz[x] += siz[y];
}
smin(ans, dp[x][m][0]), smin(ans, dp[x][m][1]), smin(ans, dp[x][m][2]);
// dbg("x = %d: ", x);
// for (int i = 1; i <= m; ++i) dbg("%d:(%d, %d, %d) ", i, dp[x][i][0], dp[x][i][1], dp[x][i][2]);
// dbg("\n");
} inline void work() {
memset(dp, 0x3f, sizeof(dp));
ans = INF;
dfs(1);
printf("%d\n", ans);
} inline void init() {
read(n), read(m);
int x, y, z;
for (int i = 1; i < n; ++i) read(x), read(y), read(z), adde(x, y, z);
} int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}

最新文章

  1. 在idea中maven项目jdk编译version总是跳到1.5
  2. dubbo-monitor图标功能不显示
  3. 微信公众号里打开链接下载APP
  4. String的内存分配
  5. mysql批量修改表引擎
  6. Android基于XMPP Smack openfire 开发的聊天室
  7. keycode按键对照表
  8. Lua基础 函数(一)
  9. How to Make LastPass Even More Secure with Google Authenticator
  10. node实现创建服务器获取wx jssdk签名
  11. 2017最新苹果 APPLE ID注册流程
  12. asp.net mvc 防止重复提交
  13. Linux(CentOs6.3)网络配置
  14. NumPy 学习笔记(一)
  15. 基于Eclipse搭建hadoop开发环境
  16. 关于Unity中的光照(三)
  17. PhoneGap安装配置
  18. Oracle text组件安装
  19. Syncovery : Google Docs protocol completely replaced with Google Drive
  20. 计算机网络透明网桥算法时间戳c++

热门文章

  1. 2,ArrayList
  2. [USACO14MAR] 破坏Sabotage(二分答案,分数规划)
  3. [CSP-S模拟测试]:Reverse(模拟+暴力+剪枝)
  4. php7新特性的理解和比较
  5. P5018对称二叉树
  6. r_action
  7. leetcode 217. 存在重复元素 (python)
  8. Git学习及使用
  9. K-th Number 【POJ - 2104】【可持久化线段树】
  10. 舔狗【2019河北省大学生程序设计竞赛 J题】