卡了巨長時間,照着別人的博客總算一點一點改對了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