uva - 1664 Conquer a New Region (并查集 修改)[1]

【题目大意】

有N个城市,N-1条路把这些城市连起来(刚好是一个树)。相邻的两个城市有一个运输容量C(i, j),而城市x到城市y的那条路的运输能力S取决与这条路上所经过的所有路中最小的那个容量。 以那一个城市为中心,到其他N-1个城市的运输能力总和最大?

【思路】

用神奇的并查集,把路按照权值从大到小排序,然后用类似Kruskal的方法不断的加入边。 对于要加入的一条路,这条路连接这城市x和y,x所在的集合为A, y所在的集合为B, 可以确定A,B集合内的所有路都比当前这条路的权值大。如果让集合B加入集合A,就是让中心城市位于集合A,那么可以确定这两个集合合并之后的总权值为: A的权值总和+B的数量*当前这条路的权值。同样算出让集合B加入集合A的情况,取两者合并后权值大的进行合并。
存在问题:1. 输出是long long 类型,那么特别注意乘法前面需要添加 longlong  

                 long long a=allcost[proot]+(long long)nums[qroot]*cost;

                2 注意区分nums和allcost数组。通过例子发现他们要取较大的。

#include<iostream>
#include<cstdio>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
#define MAX 200100
typedef struct {
	int start;
	int end;
	int cost;
} Node;
Node d[MAX];
long long allcost[MAX]= {0};
int parent[MAX];
int nums[MAX];
long long allmax;
bool mycmp(Node a, Node b) {
	return a.cost>b.cost;
}
int main() {
	bool mycmp(Node a, Node b);
	void uni(int p, int q,int cost);
	int n;
	while(scanf("%d",&n)==1) {
		for(int i=0; i<n-1; i++) {
			scanf("%d%d%d",&d[i].start,&d[i].end,&d[i].cost);
		}
		sort(d,d+n-1,mycmp);
		for(int i=1; i<=n; i++) {
			parent[i]=i;
			allcost[i]=0;
			nums[i]=1;
		}
		for(int i=0; i<n-1; i++) {
			uni(d[i].start,d[i].end,d[i].cost);
		}
		cout<<allmax<<endl;
	}
	return 0;
}
int root(int p) {
	if(p != parent[p]) {
		parent[p] = root(parent[p]);
	}
	return parent[p];
}
void uni(int p, int q,int cost) {
	int proot = root(p);
	int qroot = root(q);

	if(proot == qroot) return ;

	long long a=allcost[proot]+(long long)nums[qroot]*cost;
	long long b=allcost[qroot]+(long long)nums[proot]*cost;
	// cout<<"------"<<p<<q<<a<<b<<endl;
	if(a>b) {
		parent[qroot] = proot;
		allcost[proot]=a;
		nums[proot]+=nums[qroot];
		allmax=a;
	} else {
		parent[proot] = qroot;
		allcost[qroot]=b;
		nums[qroot]+=nums[proot];
		allmax=b;
	}


}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值