一:【题意】
- 给定一张带权图,把根节点和其他任意K个点涂成黑色
- 每个点花费为 自身点权*距离最近黑点祖先长度
- 求最小总花费
二:【解法】
- dp[u][i][z]:u子树有i个黑点,u最近黑点祖先(或自身)为z最小花费
- 枚举dp[u][i][z]和dp[v][j][z']
- if(z'!=v&&z'!=z) continue;
- 计算dp[u][i+j][z]
三:【代码】
#include<bits/stdc++.h>
#define Pair pair<int,int>
#define w first
#define to second
#define inf 1e18
#define int long long
using namespace std;
const int N=110,M=50;
vector<Pair> mp[N];int n,K;
int nw[N];
int dis[N][N];
void Dis(int u,int f,int len){
if(f!=u) dis[f][u]=len;
for(auto e:mp[u]){
int v=e.to;
Dis(v,f,len+e.w);
}
}
int dp[N][N][N];
int t[N][N];
int lim[N];
void Dp(int u){
for(auto e:mp[u]){
int v=e.to;
Dp(v);
}
dp[u][1][u]=0;
for(int i=0;i<=n;i++){
if(dis[i][u]!=inf) dp[u][0][i]=nw[u]*dis[i][u];
}
lim[u]=1;
for(auto e:mp[u]){
int v=e.to;
int up=min(K,lim[u]+lim[v]);
for(int i=0;i<=up;i++){
for(int j=0;j<=n;j++){
t[i][j]=dp[u][i][j]+dp[v][0][j];
}
}
for(int i=0;i<=up;i++){
for(int j=0;i+j<=up&&j<=lim[v];j++){
for(int z=0;z<=n;z++){
for(int z1=0;z1<=n;z1++){
if(z1!=v&&z1!=z) continue;
t[i+j][z]=min(t[i+j][z],dp[u][i][z]+dp[v][j][z1]);
}
}
}
}
lim[u]=up;
for(int i=0;i<=lim[u];i++){
for(int j=0;j<=n;j++){
dp[u][i][j]=t[i][j];
}
}
}
}
signed main(){
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
dis[i][j]=inf;
for(int k=0;k<N;k++){
dp[i][j][k]=inf;
}
}
}
cin>>n>>K;
K++;
for(int i=1;i<=n;i++){
cin>>nw[i];
int fa,w;cin>>fa>>w;
mp[fa].push_back({w,i});
}
for(int i=0;i<=n;i++) Dis(i,i,0);
Dp(0);
cout<<dp[0][K][0]<<"\n";
return 0;
}
//dp[u][i][z]:u子树有i个黑点,u最近黑点祖先(或自身)为z最小花费
//dp[u][i+j][z]
//if(z'!=v&&z'!=z) continue;
//dp[u][i][z]+dp[v][j][z']
//begin:dp[u][1][u]=0,dp[u][0][f]=nw[u]*dis(f,u)
//ans:dp[0][K][0]
//wufu