您的位置:首页 > 其它

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

2017-08-02 13:31 344 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: