zoukankan      html  css  js  c++  java
  • ccf 201909-5

    #include <bits/stdc++.h>
    
    using namespace std;
    
    //dp[u][p]表示以u为根节点的树,选取了p个重要结点的距离之和的最小值 
    
    const int maxn = 5e4+100;
    int head[maxn];    //存以i为起点的最近加入的一条边的存储位置 
    int tot;        //边的编号 
    
    int dp[maxn][102];    //dp[u][p]:以u为根节点选取p个重要节点的最小权值 
    int k;
    bool good[maxn];    //是否是重要节点 
    int num[maxn];        //以u为根节点的树中重要节点的个数 
    int tree_u_v[102];    //临时变量区 
    
    struct Node{        //链式前向星 struct
        int to;        //边的终点     
        int w;        //权值 
        int next;    //相同起点的上一次加入的边的存储位置 
    }edge[maxn*2];
    
    void init(){
        tot = 0;
        memset(head,-1,sizeof(head));    //将head初始化为-1 
    }
    
    void add_edge(int from, int to, int w){        //from起点, to终点, w权值 
        edge[tot].to=to;
        edge[tot].w=w;
        edge[tot].next=head[from]; //head[from]:上一次加入的边的位置 
        head[from]=tot++;          //更新以from为起点的最新加入的边的编号 
    }
    
    void dfs(int u, int fa){    //u节点,fa:u的父亲 
        dp[u][0]=0;            //选取0个重要节点,权值为0 
        if(good[u]){        //如果u本身是重要节点 
            dp[u][1]=0;        //选自己,但是有一个节点,所以权值还是0 
            num[u]=1;
        }
        for(int i=head[u]; i!=-1; i=edge[i].next){        //遍历u的邻接点 
            if(edge[i].to == fa)    continue;
            int v = edge[i].to;
            int w = edge[i].w;
            dfs(v,u);                //dfs u的子节点 
            for(int j=0;j<=k;j++)    tree_u_v[j] = dp[u][j];        //保留更新前的数据 
            int nU = min(k,num[u]);            //最多不能超过k 
            int nV = min(k,num[v]);
            num[u]+=num[v];
            for(int j=0;j<=nU;++j){            //不明白 ! 
                for(int t=0; t<=nV && t+j<=k; ++t)        //j、t、状态转移方程 不理解 
                    dp[u][j+t] = min(1ll*dp[u][j+t], 1ll*(k-t)*t*w + tree_u_v[j] + dp[v][t]);
            }                     //要乘 1ll 否则会溢出 
        }
    }
    
    int main(){
        int n,m,x,y,d;
        scanf("%d %d %d",&n,&m,&k);
        for(int i=0;i<m;i++){
            scanf("%d",&x);
            good[x]=true;
        }
        init();
        for(int i=1;i<n;i++){
            scanf("%d %d %d",&x,&y,&d);
            add_edge(x,y,d);
            add_edge(y,x,d);
        }
        memset(dp,0x3f,sizeof(dp));
        dfs(1,-1);
        printf("%d
    ",dp[1][k]);
        return 0;
    }

    先码住

  • 相关阅读:
    1136 A Delayed Palindrome (20 分)(回文数)
    1117 Eddington Number (25 分)(简单逻辑)
    1094 The Largest Generation (25 分)(BFS,DFS树的遍历)
    1079 Total Sales of Supply Chain (25 分)(dfs,bfs,树的遍历)
    还原前端代码js.map
    构造表单任意文件上传
    Python搭建HTTP服务
    C# 递归算法
    foreach小结
    判断一个点是否在一个区域中
  • 原文地址:https://www.cnblogs.com/shiliuxinya/p/12037802.html
Copyright © 2011-2022 走看看