卡了巨长时间,照着别人的博客总算一点一点改对了TAT,对树形分组背包模板改写一下,有时间的话再补细节。
参考博客:https://blog.csdn.net/qq_40531479/article/details/103211677?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
#include <bits/stdc++.h> #define N 50005 using namespace std; int n,m,k,tot=0,head[N],ver[2*N],Next[2*N],edge[2*N];//存双向边 long long dp[N][105];//dp[i][j]表示从以i为根的子树里(包括自己)选取j个重要节点的总路径的最小值 bool imp[N]; int num[N];//num[i]存储i为根的树的重要节点的个数 void add(int x,int y,int z) { ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot; } void dfs(int x,int pre)//返回的是当前以x为根的树所含重要节点的个数 { dp[x][0]=0; int i,j,q; if(imp[x]) { dp[x][1]=0;//只选自己 num[x]=1; } for(i=head[x];i;i=Next[i]) { int y=ver[i],z=edge[i]; if(y==pre)continue; dfs(y,x); num[x]+=num[y]; int nX = min(k,num[x]); //因为最多选K个重要节点,所以可以取一个num[u]和K的最小值,避免多余的计算 int nY = min(k,num[y]);//同上 for(j=nX;j>=1;j--) { for(q=1;q<=min(j,nY);q++)////??? { dp[x][j]=min(dp[x][j],dp[x][j-q]+dp[y][q]+z*(k-q)*q);//有点类似点分治的意思? } } } //上面是x非重要节点的情况 下面要另外考虑x是重要节点的情况 ?????? // if(imp[x]) // { // int i; // for(i=k;i>=1;i--) // { // if(dp[x][i-1]!=0x3f3f3f3f)dp[x][i]=dp[x][i-1]; // } // } } int main() { cin>>n>>m>>k; int i,j; memset(dp,0x3f3f3f3f,sizeof(dp)); for(i=1;i<=m;i++) { int temp; scanf("%d",&temp); imp[temp]=1; } for(i=1;i<=n-1;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } dfs(1,-1); cout<<dp[1][k]; // cout<<endl; // for(i=1;i<=n;i++) // { // for(j=1;j<=k;j++)cout<<dp[i][j]<<' '; // cout<<endl; // } return 0; } //5 3 2 //1 3 5 //1 2 4 //1 3 5 //1 4 3 //4 5 1