-----dfs+思維 hdu 6060-RXD and dividing

http://acm.hdu.edu.cn/showproblem.php?pid=6060 傳送門

題目大意:
有一棵樹T,n個點,n-1條邊;將2,3,4,5,6,… n分到k個集合裏面S1,S2,S3,… Sk;集合可以是空集,並且任意兩個集合之間沒有相同的點;定義一個函數f(S)=f({1}USi)爲集合S中的最小斯坦納樹,即爲每個集合中所有點加編號爲1的節點相互連接所經過的邊的權值之和,求k個點集權值最大的和;
如:對於Si={3,4},f(S)=f({1}U{3,4})的值爲點1點2再到點3的值,加上點1到點2再到4的值之和;

解題思路:首先要知道,題目中所給的樹就是一顆最小生成樹,然後求f(S)=f({1}USi);
用題目給的樣例來解釋一下:
k=4,要求把2-5分到4個集合裏面,當然有些集合可以是空集
1.沒有空集的時候,S1={2},S2={3},S3={4},S4={5};
f(S1)=f({1}U{2})=3; f(S2)=f({1}U{3})=7; f(S3)=f({1}U{4})=8; f(S4)=f({1}U{5})=9;
res=f(S1)+f(S2)+f(S3)+f(S4)=27;
2.有1個空集,{2,3},{4},{5},{空集},res=24,其餘兩種相同

3.有2個空集,{2,3,4},{5},{空集},{空集},res=21,還有兩種情況res值相同

4.有3個空集,{2,3,4,5},{空集},{空集},{空集},res=18;
由上可知,空集的存在只會使得res變小,題目要求求最大res,所以就應該把2-n分到的k個集合中,並且集合裏面沒有空集的存在

求最大的res,而res是由邊權加起來的,也就是說我們加上的邊越多,res越大,所以應該儘量使得每條邊都應該被走到;
這裏寫圖片描述
如上圖:考慮邊A-C所做的貢獻,目的使得A-C邊被走的多一些,所以應該使得C點或者C點的子節點屬於集合中,那麼邊A-C就會被走過;並且應該儘量使得C點或者C點的子節點分佈於更多的集合中;設C點和C點的子節點數爲sum;

/*若是 sum<k,這個時候C點和C點的子節點最多能分到sum個集合裏面,A-C邊最多被走過sum次
若是 sum>k,這個時候C點和C點的子節點最多能分到k個集合裏面,A-C邊最多被走過k次*/


#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

typedef long long LL;
const int maxn=1e7+10;

typedef long long LL;
int n,k,tot;
int head[maxn],siz[maxn];
int w[maxn];
struct
{
    int from,to,val,next;
} G[maxn*2];
void add_edge(int from,int to,int val)
{
    G[tot].from=from;
    G[tot].to=to;
    G[tot].val=val;
    G[tot].next=head[from];
    head[from]=tot;
    tot++;
}
void dfs(int x,int father_x)
{
    siz[x]=1;
    for(int i=head[x]; i!=-1; i=G[i].next)
    {
        int to=G[i].to;
        if(to==father_x) continue;
        w[to]=G[i].val;
        dfs(to,x);
        siz[x]+=siz[to];
    }
}
int main()
{
    int a,b,c;
    while(~scanf("%d%d",&n,&k))
    {
        memset(head,-1,sizeof(head));
        memset(siz,0,sizeof(siz));
        memset(w,0,sizeof(w));
        tot=0;
        for(int i=1; i<=n-1; i++) ///n-1條邊
        {
            scanf("%d%d%d",&a,&b,&c);
            add_edge(a,b,c);  
        }
        dfs(1,-1);
        LL ans=0;
        for(int i=1; i<=n; i++)
            ans+=(LL)w[i]*min(k,siz[i]);
        printf("%lld\n",ans);
    }
}

發佈了53 篇原創文章 · 獲贊 14 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章