思路:
将点之间的距离和转化为边的贡献。
和这个题一模一样。
2018银川邀请赛 G - Factories Gym - 102222G(树形DP)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll INF = 1e18;
const int maxn = 1e5 + 7;
int head[maxn << 1],nex[maxn << 1],to[maxn << 1],val[maxn << 1],tot;
int deg[maxn],siz[maxn],vis[maxn];
ll f[maxn][105];
int n,k;
void add(int x,int y,int z)
{
to[++tot] = y;
nex[tot] = head[x];
val[tot] = z;
head[x] = tot;
}
void init1()
{
tot=0;
for(int i = 1;i <= n;i++)
{
deg[i] = siz[i] = head[i] = vis[i] = 0;
}
for(int i = 1;i <= n;i++)
{
head[i + n] = 0;
}
}
void init2()
{
for(int i = 1;i <= n;i++)
{
f[i][0] = 0;
for(int j = 1;j <= k;j++)f[i][j] = INF;
if(vis[i] == 1)
{
f[i][1] = 0;
siz[i] = 1;
}
}
}
void DP(int u,int fa)
{
for(int i = head[u];i;i = nex[i])
{
int v = to[i],w = val[i];
if(v == fa)continue;
DP(v,u);
siz[u] += siz[v];
for(int i = min(k,siz[u]);i >= 1;i--)
{
for(int j = 1;j <= min(i,siz[v]);j++)
{
f[u][i] = min(f[u][i],f[u][i - j] + f[v][j] + w * (k - j) * j);
}
}
}
}
int main()
{
int kase = 0;
int m;
scanf("%d%d%d",&n,&m,&k);
init1();
for(int i = 1;i <= m;i++)
{
int x;scanf("%d",&x);
vis[x] = 1;
}
for(int i = 1;i < n;i++)
{
int x,y,z;scanf("%d%d%d",&x,&y,&z);
add(x,y,z);add(y,x,z);
deg[x]++;deg[y]++;
}
int rt = 1;
init2();
DP(rt,0);
printf("%lld\n",f[rt][k]);
return 0;
}