算法:ZOJ 3659 Conquer a New Region(并查集)

【题目大意】

有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的情况,取两者合并后权值大的进行 合并。

【代码】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<utility>
#include<set>
#include<queue>
#include<algorithm>
using namespace std;  

typedef long long int64;  

const int INF = 0x3f3f3f3f;
const int MAXN = 200010;
const double eps = 1e-7;
int n;
int f[MAXN], cnt[MAXN];
int64 sum[MAXN];  

struct Edge{
    int a, b, w;
    bool operator<(const Edge&rhs) const{
        return w > rhs.w;
    }
}arr[MAXN];  

void init(){
    for(int i=0; i<=n; ++i){
        f[i] = i;
        cnt[i] = 1;
        sum[i] = 0;
    }
}  

int find(int x){
    int i, j=x;
    while(j != f[j]) j = f[j];
    while(x != j){ i=f[x]; f[x]=j; x=i; }
    return j;
}  

int main(){  

    while(~scanf("%d", &n)){  

        for(int i=0; i<n-1; ++i)
            scanf("%d%d%d", &arr[i].a, &arr[i].b, &arr[i].w);  

        init();
        sort(arr, arr+n-1);  

        int64 ans = 0;
        for(int i=0; i<n-1; ++i){
            int ra=find(arr[i].a), rb=find(arr[i].b);
            int64 toa = (int64)cnt[rb]*arr[i].w + sum[ra];
            int64 tob = (int64)cnt[ra]*arr[i].w + sum[rb];
            if(toa > tob){
                f[rb] = ra;
                sum[ra] = toa;
                cnt[ra] += cnt[rb];
            }else{
                f[ra] = rb;
                sum[rb] = tob;
                cnt[rb] += cnt[ra];
            }
            ans = max(ans, max(toa, tob));
        }
        cout << ans << endl;
    }
    return 0;
}

查看本栏目更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/sjjg/

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索int
, include
, const
, zoj
, 一个
, 城市
, 并查集
总和
new region参数、并查集、带权并查集、可持久化并查集、并查集 路径压缩,以便于您获取更多的相关知识。

时间: 2024-09-28 20:47:15

算法:ZOJ 3659 Conquer a New Region(并查集)的相关文章

[算法系列之二十八]并查集(不相交集合)

一 概述 并查集(Disjoint set或者Union-find set)是一种树型的数据结构,常用于处理一些不相交集合(Disjoint Sets)的合并及查询问题. 有一个联合-查找算法(union-find algorithm)定义了两个操作用于此数据结构: Find:确定元素属于哪一个子集.它可以被用来确定两个元素是否属于同一子集. Union:将两个子集合并成同一个集合. 因为它支持这两种操作,一个不相交集也常被称为联合-查找数据结构(union-find data structur

经典算法题每日演练——第十五题 并查集

原文:经典算法题每日演练--第十五题 并查集     这一篇我们看看经典又神奇的并查集,顾名思义就是并起来查,可用于处理一些不相交集合的秒杀. 一:场景     有时候我们会遇到这样的场景,比如:M={1,4,6,8},N={2,4,5,7},我的需求就是判断{1,2}是否属于同一个集合,当然实现方法 有很多,一般情况下,普通青年会做出O(MN)的复杂度,那么有没有更轻量级的复杂度呢?嘿嘿,并查集就是用来解决这个问题的.   二:操作   从名字可以出来,并查集其实只有两种操作,并(Union)

图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用

图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 B(G).其中 T(G)是遍历图时所经过的边的集合,B(G) 是遍历图时未经过的边的集合.显然,G1(V, T) 是图 G 的极小连通子图,即子图G1 是连通图 G 的生成树. 深度优先生成森林   右边的是深度优先生成森林: 连通图的生成树不一定是唯一的,不同的遍历图的方法得到不同的生成树;从不

zoj 3261 Connections in Galaxy War:逆向并查集

链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3261 题目: Connections in Galaxy War Time Limit: 3 Seconds      Memory Limit: 32768 KB In order to strengthen the defense ability, many stars in galaxy allied together and built many bidi

算法起步之并查集(不相交集合数据结构)

原文:算法起步之并查集(不相交集合数据结构)          在java中经典的数据结构基本都给实现好了,我们可以直接调用,但是并查集这种数据结构却没有很好的替代工具,在这里我们我们自己去实现并查集数据结构.首先我们先要去了解什么是并查集.并查集也是一种非常经典常用的数据结构.像求连通子图跟我们下面要研究的最小生成树问题都会用到并查集.并查集就是能够实现若干个不相交集合,较快的合并和判断元素所在集合的操作.不相交集合:一个不相交集合维护了一个不相交动态集合{s1,s2,s3--}我们用一个代表

C++并查集亲戚(Relations)算法实例_C 语言

本文实例讲述了C++并查集亲戚(Relations)算法.分享给大家供大家参考.具体分析如下: 题目: 亲戚(Relations) 或许你并不知道,你的某个朋友是你的亲戚.他可能是你的曾祖父的外公的女婿的外甥的表姐的孙子.如果能得到完整的家谱,判断两个人是否亲戚应该是可行的,但如果两个人的最近公共祖先与他们相隔好几代,使得家谱十分庞大,那么检验亲戚关系实非人力所能及.在这种情况下,最好的帮手就是计算机. 为了将问题简化,你将得到一些亲戚关系的信息,如同Marry和Tom是亲戚,Tom和B en是

hdu 4424 Conquer a New Region

点击打开链接hdu 4424 题意: 有n个点n-1条边,现在规定i-j的路的最大负载量为i到j所经过的所有边的最小值,要求以某个点为中心然后求出这个中心点到所有点的负载量之和最大 思路: 并查集 分析: 1 n个点n-1条边很明显给定的这个关系就是一棵树 2 那么我们利用并查集,先对边按照权值从大到小排序,然后每一次在加入一条边的时候根据选择的中心点是在哪一个集合里面得到的和最大,那么我们就选择最大的那个,最后合并成一个集合答案就是随便一个点的根节点的rank值 代码: #include<cs

中奖算法-现在微信朋友圈里有一种叫集字中奖的营销活动,奖品数量一定的情况下,实现中奖分配的算法是?

问题描述 现在微信朋友圈里有一种叫集字中奖的营销活动,奖品数量一定的情况下,实现中奖分配的算法是? 例如: 不好意思没有c币--

并查集算法

#include <iostream> #include <cstring> #include <string> using namespace std; const int MAX_NUM = 100; string name[MAX_NUM]; int group[MAX_NUM]; int rank[MAX_NUM]; void MakeSet() { for (int i = 0; i < MAX_NUM; ++i) { group[i] = i; ran