HDU 4424

 题意描述:现有N-1个点,每两个点间一条道路,且任意两点之间只有一条路径,每条道路有一个货物容量,两点之间的最大货物容量是其路径中道路的货物容量最小值。先要选  择一点,使得它到其他N-1个点的货物容量总和最小。

 分析 :

  T-T 还是没能全靠自己做出来。

  想到了按照边的权值从大到小排序,但是并不知道怎么合并,也无法证明贪心的正确性。

  看了题解之后也想了好半天才想明白了贪心的原因(为什么他们的题解都各种想当然T-T)。每一次合并实际上都是在选择以左端所在集合的根节点为基点还是选择以右端所在集合的根节点为基点,当最后一步将两个集合合并后,得到最终答案。

  如果选择左端,则最终的结果为  左端原权值+右边端点数*这条边的容量。

  如果选择右端,则最终的结果为  右边原权值+左边端点数*这条边的容量。

  比较可知如何合并。

  然后还因为long long WA了一次。。真是醉。。

  Memroy :    7892 Time: 1372

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200000+10;

struct Edge{
    int x,y;
    long long value;
}edge[maxn];

bool cmp(Edge a,Edge b){
return a.value>b.value;
}

int n;
int pa[maxn],cnt[maxn];
long long v[maxn];
void init(){
for(int i=0;i<n-1;i++){edge[i].x=0;edge[i].y=0;edge[i].value=0;}
for(int i=1;i<=n;i++){ pa[i]=i;v[i]=0;cnt[i]=1;}
}

int findset(int x){
    if(pa[x]==x)return x;
    else return pa[x]=findset(pa[x]);
 }

int main(){

while(scanf("%d",&n)==1){
    init();
    for(int i=0;i<n-1;i++){
        scanf("%d%d%lld",&edge[i].x,&edge[i].y,&edge[i].value);
    }
sort(edge,edge+n-1,cmp);
for(int i=0;i<n-1;i++){
 int x=findset(edge[i].x);
 int y=findset(edge[i].y);
 if(v[x]+edge[i].value*cnt[y]>v[y]+edge[i].value*cnt[x]){
  pa[y]=x;
  v[x]=v[x]+edge[i].value*cnt[y];
  cnt[x]=cnt[x]+cnt[y];
 }
 else{
  pa[x]=y;
  v[y]=v[y]+edge[i].value*cnt[x];
  cnt[y]=cnt[y]+cnt[x];
 }
}
printf("%lld\n",v[findset(1)]);
}
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值