zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    线程同步(一)
    java守护线程
    C/C++中如何获取数组的长度?
    java操作xml方式比较与详解(DOM、SAX、JDOM、DOM4J)
    按单词逆序句子(含标点)
    常见误区(一)
    java创建XML及开源DOM4J的使用
    C++学习(一)
    java读XML文件
    MiniProfiler 兼容 Entity Framework 6
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/12608143.html
Copyright © 2011-2022 走看看