HDU 6060 RXD and dividing

 

 

RXD and dividing

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 2140    Accepted Submission(s): 912


 

Problem Description

RXD has a tree T, with the size of n. Each edge has a cost.
Define f(S) as the the cost of the minimal Steiner Tree of the set S on tree T. 
he wants to divide 2,3,4,5,6,…n into k parts S1,S2,S3,…Sk,
where ⋃Si={2,3,…,n} and for all different i,j , we can conclude that Si⋂Sj=∅. 
Then he calulates res=∑ki=1f({1}⋃Si).
He wants to maximize the res.
1≤k≤n≤106
the cost of each edge∈[1,105]
Si might be empty.
f(S) means that you need to choose a couple of edges on the tree to make all the points in S connected, and you need to minimize the sum of the cost of these edges. f(S) is equal to the minimal cost 

 

 

Input

There are several test cases, please keep reading until EOF.
For each test case, the first line consists of 2 integer n,k, which means the number of the tree nodes , and k means the number of parts.
The next n−1 lines consists of 2 integers, a,b,c, means a tree edge (a,b) with cost c.
It is guaranteed that the edges would form a tree.
There are 4 big test cases and 50 small test cases.
small test case means n≤100.

 

 

Output

For each test case, output an integer, which means the answer.

 

 

Sample Input

 

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

 

 

Sample Output

 

27

题意:给你一棵无向带权树,你要把2~n号节点划分成k个部分。使每个部分并上1号节点的斯坦纳树值总和最大。

官方题解:

个人见解:不妨当成一个构造题。

首先 k=1就是所有边的权值和。

k=2,显然叶子结点划成一个集合,非叶节点划分成一个集合。这样答案最大。因为这样能使非叶节点的边数贡献增加到最大值。

k>=3时,我们取一颗子树u(以u为根的子树),考虑u的父边权值w的贡献。

假设子树大小为siz[u],若k>siz[u],我们显然可以每个节点划分成一部分,这是所有情况中最理想的情况。

如果有另一颗子树v,k也>siz[v](v在u内或者包含u就和上面一样,我们假设v不在u内且不包含u)

那么u,v两棵子树中的划分可以合并成max(siz[u],siz[v])个,并保持上述结果。

也就是说 无论多少颗互不包含的子树,若k>这些子树的size,那么一定可以划分成max(siz[i])部分,使w的贡献值达到最大。

若k<=siz[u] 除去本来就包含该节点的一次划分,我们考虑把其子树划分成k-1份。

无论怎么划分,w一定是贡献k次。(即按照子树刚才的那样过划分,能保持子树划分的贡献值不变)

因此dfs一遍,答案就是所有节点u的父边权值w*min(siz[v],k)的和。

好好想想上面的过程。有其他想法或者指正错误欢迎评论区留言。(因为我其实还不是想的很清楚)

代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1000010;
const ll mo=1e9+7;
ll n,m,k,q,l,r;
struct node
{
    ll v,w;
    node();
    node(ll q,ll o){v=q;w=o;}
};
vector<node>vc[maxn];
ll sum;
ll siz[maxn];
bool vis[maxn];
ll ans,ct,cnt,tmp,flag;
void dfs(ll u,ll fa,ll w)
{
    siz[u]++;
    for(int i=0;i<vc[u].size();i++)
    {
        node kk=vc[u][i];
        if(kk.v==fa) continue;
        dfs(kk.v,u,kk.w);
        siz[u]+=siz[kk.v];
    }
    ans+=min(k,siz[u])*w;
}
int main()
{
    int T,cas=1;
    while(scanf("%lld%lld",&n,&k)!=EOF)
    {
        flag=1;ans=0;
        int aa=0,bb=-1;
        for(int i=1;i<=n;i++)
        {siz[i]=0;vc[i].clear();}
        for(int i=1;i<n;i++)
        {
            ll x,y,z;
            scanf("%lld%lld%lld",&x,&y,&z);
            vc[x].push_back(node(y,z));
            vc[y].push_back(node(x,z));
        }
        ans=0;
        dfs(1,-1,0);
        printf("%lld\n",ans);
      //  if(flag) puts("Yes"); else puts("No");
    }
    return 0;
}
/*
999
5 2
1 2 3 4 5
3 2
2 1 3
*/

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值