hdu6060-思维&搜索&好题-RXD and dividing

来源:互联网 发布:即将失效请记好新域名 编辑:程序博客网 时间:2024/06/05 08:03

http://acm.hdu.edu.cn/showproblem.php?pid=6060
给定一个树,问你把除了1节点之外的节点 分成k份,然后让每一份和1节点 连接成 最小的斯坦纳树(最小生成树是一种特殊的斯坦纳树,所以斯坦纳树就是把所有的节点连通的树。),而图中已经是树了,所以其实就是把他们连接起来(就是题中对应的f函数,但是已经是树了所以不存在最小一说。。连起来只有一种情况啊)。问你最大的花费是多少。
比赛的时候连题意都读错了,因为 k个集合包含了所有的点,所以必然有好多边要重复计算,我们如果想要最大的话,必须让其尽可能多的重复计算。于是就可以构建下图中的情况qwq
这里写图片描述
(图中假定k是3,若大于3,那么中间那两个点应该换成其他颜色,希望更多的和1节点邻接的边的重用 !)
即尽可能的让其子树充满不同的颜色(集合)。取一个 k和siz的 最小值。
一次dfs就可以了。。

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int maxn=2e6+12;struct Node{     int to;     int cost;     Node(){};     Node(int _a,int _b){to=_a;cost=_b;}};vector<Node>G[maxn];int siz[maxn];int vc[maxn];void dfs(int u,int fa){    //cout<<"!!!!"<<endl;   siz[u]=1;    for(int i=0;i<G[u].size();i++){           int v=G[u][i].to;           if(v==fa) continue;           dfs(v,u);           vc[v]=G[u][i].cost;           siz[u]+=siz[v];    }        //if(!flag) siz[u]=1;    return ;}int main(){   int m,k;     int a,b,c;    while(~scanf("%d%d",&m,&k)){         for(int i=0;i<maxn;i++)             G[i].clear();         for(int i=0;i<m-1;i++){             scanf("%d%d%d",&a,&b,&c);             G[a].push_back(Node(b,c));             G[b].push_back(Node(a,c));         }         dfs(1,-1);         //puts("!!!");         ll all=0;         for(int i=2;i<=m;i++){            all+=1ll*min(siz[i],k)*vc[i];         }         printf("%lld\n",all);    }    return 0;}
原创粉丝点击