题目链接

problem

给出一棵树,每个点有点权,每条边有边权。0号点为根,每个点的代价是这个点的点权\(\times\)该点到根路径上的边权和。

现在可以选择最多K个点。使得每个点的代价变为:这个点的点权\(\times\)改点到最近的被选中的一个祖先的边权和。

问所有点的代价和最小为多少。

solution

用\(g[i][j]\)表示以i为根的子树,强制选i,最大的贡献(这里的贡献是指比什么也不选所减少的代价。)

最终答案肯定就是初始代价-g[0][k]

考虑怎么维护出\(g\)。用\(f[i][j]\)表示以\(i\)为根的子树,\(i\)可选可不选。然后树形背包一下就可以求出g。

考虑怎么维护f。每当枚举到一个根的时候,就重新dfs一遍这棵子树,初始f[x][0]=w[x]*dep[u]。dep[u]表示从枚举的根到0号点的距离。然后同样方法背包一遍,就可以维护处\(f\)。

把j写成k调了一上午。。。。

code

/*
* @Author: wxyww
* @Date: 2019-12-21 10:08:12
* @Last Modified time: 2019-12-21 11:04:12
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 110;
ll read() {
ll x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1; c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar();
}
return x * f;
}
int siz[N],f[N][55],g[N][N],dep[N],w[N],n,K;
struct node {
int v,nxt;
}e[N];
int head[N],ejs;
void add(int u,int v) {
e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;
}
void dp(int u,int W) {
f[u][0] = W * w[u];
for(int i = head[u];i;i = e[i].nxt) {
int v = e[i].v;
dp(v,W);
for(int j = min(K,siz[u]);j >= 0;--j) {
for(int k = 0;k <= min(j,siz[v]);++k) {
f[u][j] = max(f[u][j],f[v][k] + f[u][j - k]);
}
}
}
for(int i = 1;i <= K;++i) f[u][i] = max(f[u][i],g[u][i]);//在算上强制选的答案
}
void dfs(int u) {
siz[u] = 1;
for(int i = head[u];i;i = e[i].nxt) {
dep[e[i].v] += dep[u];
dfs(e[i].v);
siz[u] += siz[e[i].v];
} g[u][1] = dep[u] * w[u]; memset(f,0,sizeof(f)); for(int i = head[u];i;i = e[i].nxt) {
int v = e[i].v;
dp(v,dep[u]);
for(int j = min(K,siz[u]);j >= 1;--j) {
for(int k = 0;k < j;++k) {
g[u][j] = max(g[u][j],g[u][j - k] + f[v][k]);
}
}
}
// if(u == 1) cout<<g[1][1]<<endl;
}
int main() {
// freopen("1.in","r",stdin);
n = read(),K = read();
++K;
for(int i = 1;i <= n;++i) {
w[i] = read();int u = read();add(u,i);
dep[i] = read();
}
dfs(0);
int ans = 0;
for(int i = 1;i <= K;++i) ans = max(ans,g[0][i]);
// cout<<g[2][1];
for(int i = 1;i <= n;++i) ans -= dep[i] * w[i];
cout<<-ans<<endl;
return 0;
}

最新文章

  1. [板子]倍增LCA
  2. sh5.while 脚本练习
  3. 多进程模块multiprocessing的使用
  4. 16.检查是否为BST
  5. Umbraco文档类型定义多个template
  6. running android lint has encountered a problem
  7. Maven系列--&quot;maven-compiler-plugin&quot;的使用、Maven之Surefire插件
  8. emacs window版环境配置(设置默认的.emacs文件,指向自定义.emacs达到自定义home的目的)
  9. vi/vim多行注释和取消注释
  10. Codeforces 556 A Case of the Zeros and Ones
  11. 【JavaWeb】JDBC连接MySQL数据库
  12. Babel presets stage
  13. 我的代码-normalize
  14. 算法——001BitMap(位图)算法
  15. html提交表单到Servlet
  16. ORA-12514 TNS:LISTENER DOES NOT CURRENTLY KNOW OF SERVICE REQUESTED IN CONNE
  17. DevExpress gridcontrol gridView主从表折叠/展开显示
  18. Java第01次实验提纲(基本概念+编程环境入门+PTA)
  19. java 中一些需要注意的知识点
  20. IoC容器之Unity

热门文章

  1. JS---part2课程介绍+part1复习
  2. cocos2d游戏jsc文件格式解密,SpideMonkey大冒险
  3. ksoap2 android 调用WebService
  4. IDEA项目更改项目名
  5. 拥抱自动化,CODING 2.0 持续集成全新上线
  6. MySQL数据库~~~~~索引
  7. Java基础 - volatile
  8. MySql索引背后的数据结构及算法
  9. SSM实现mysql数据库账号密码加密连接
  10. 03-JVM-垃圾回收算法