CSP 201909-5 城市规划(树形DP)

卡了巨长时间,照着别人的博客总算一点一点改对了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
原文地址:https://www.cnblogs.com/lipoicyclic/p/12608143.html