首页 > 其他 > 详细

gym102222 G. Factories

时间:2019-12-05 11:30:18      阅读:61      评论:0      收藏:0      [点我收藏+]

gym102222 G. Factories

地址

题目大意:

给一棵n个点的树,选m个点,这m个点只能在叶子节点上,问着m个点中两两之间到达其余各点的距离和最小值是多少
题解:
任意两点的树上距离和问题应从边的贡献角度考虑。

树形dp
设 f[u][i] 表示以 u 为根的子树中,选了 i 个叶子节点的最优解,状态转移方程为:

f[u][i+j]=min(f[u][i+j],f[u][i]+f[v][j]+w∗j∗(j−m))


其中所加项为子节点和父节点之间的边的贡献

/*
[HAOI2015]树上染色  的弱化版 
*/ 
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int T,n,m,cas;
int main(){
    for(scanf("%d",&T);T--;){
        scanf("%d%d",&n,&m);
        vector<vector<pair<int,ll> > >e(n+1);
        for(int i=1,x,y,z;i<n;i++){
            scanf("%d%d%d",&x,&y,&z);
            e[x].emplace_back(y,z);
            e[y].emplace_back(x,z);
        }
        if(m==1){printf("Case #%d: 0\n",++cas);continue;}
        if(n==2){printf("Case #%d: %lld\n",++cas,e[1][0].second);continue;}
        vector<vector<ll> > f(n+1,vector<ll>(m+1,1e14));vector<int>siz(n+1,0);
        function<void(int,int)>dfs=[&](int u,int fa)->void{
            bool leaf=1;
            f[u][0]=0;
            for(auto t:e[u]){
                int v=t.first;ll w=t.second;
                if(v==fa) continue;
                leaf=0;
                dfs(v,u);
                for(int i=min(siz[u],m);~i;i--){
                    for(int j=min(siz[v],m-i);~j;j--){
                        f[u][i+j]=min(f[u][i+j],f[u][i]+f[v][j]+w*(m-j)*j);
                    }
                }
                siz[u]+=siz[v];
            }
            if(leaf){f[u][1]=0;siz[u]=1;}
        };
        int rt=0;
        for(int i=1;i<=n;i++) if(e[i].size()>1){rt=i;break;}
        dfs(rt,0);
        printf("Case #%d: %lld\n",++cas,f[rt][m]);
    }
    return 0;
}

 

gym102222 G. Factories

原文:https://www.cnblogs.com/shenben/p/11987922.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!