hdu6060斯坦纳树

本文介绍了解决HDU6060问题的方法,该问题是关于求解一棵树中特定节点组成的最小斯坦纳树的最大权值总和。通过将问题转化为节点标号分配问题,并利用DFS遍历计算子树大小,最终得出时间复杂度为O(n)的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

hdu6060
题意:给出一颗n个节点的树,要求将2-n号节点分成k部分,然后再将每一部分加上1号节点联通的最小花费,定义为每一部分的val,为其在原图上的最小斯坦纳树,问总的val最大可能是多少。

把1看成整棵树的根. 问题相当于把2∼n每个点一个[1,k]的标号. 然后根据最小斯坦纳树的定义(x,fa(x) ),(x,fa(​x)​​ ) 这条边的贡献是 x 子树内不同标号的个数目dif(​i)​​ . 那么显然有dif(i)≤min(k,sz(i)),sz(​i)​​ 表示子树大小. 可以通过构造让所dif(​i)​​ 都取到最大值. 所以答案就是 w[x] ∗min( sz(x) , k ),时间复杂度O(n),w[x]表示点x与其父节点的连边的权值。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
typedef long long LL;
using namespace std;
const LL MAXN=1e6+10;
struct node
{
    LL next,v;
    LL w;
} edge[MAXN*2];

LL head[MAXN],tot;
LL son[MAXN];
LL dis2[MAXN];
LL n,k;
void add(LL u,LL v,LL  w)
{
    edge[tot].v=v;
    edge[tot].w=w;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void init()
{
    memset(head,-1,sizeof(head));
    tot=0;
}
void dfs(LL u,LL pre)
{
    son[u]=1;
    LL v;
    for(LL i=head[u]; i!=-1; i=edge[i].next)
    {
        v=edge[i].v;
        if(v==pre)
            continue;
        dis2[v]=edge[i].w;
        dfs(v,u);
        son[u]+=son[v];
    }
}
int main()
{
    LL u,v,w;
    while(scanf("%lld%lld",&n,&k)!=-1)
    {
        init();
        for(LL i=1; i<n; i++)
        {
            scanf("%lld%lld%lld",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
        }
        dfs(1,-1);
        LL sum=0;
        for(LL i=2; i<=n; i++)
            sum+=(LL)(dis2[i]*min(son[i],k));

        printf("%lld\n",sum);
    }
    return 0;
}
/**
5 2
1 2 3
2 3 4
2 4 5
2 5 6

6 1
1 2 1
1 3 2
1 4 3
2 5 5
2 6 6

5 2
1 2 3
2 3 4
3 4 5
3 5 6
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值