• 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;
    }

    先码住

  • 相关阅读:
    EasyUI中datagrid的行编辑模式中,找到特定的Editor,并为其添加事件
    easyui datagrid plunges 扩展 插件
    jQuery EasyUI DataGrid Checkbox 数据设定与取值
    Easyui Tree方法扩展
    记账凭证
    部分扩展功能总结
    凭证
    voucer
    Box2D 一、学习资料(库、pdf)
    EUI EXML内部类Skin和ItemRenderer
  • 原文地址:https://www.cnblogs.com/shiliuxinya/p/12037802.html
Copyright © 2020-2023  润新知