34

扩展域并查集

 3 years ago
source link: http://www.cnblogs.com/IzayoiMiku/p/13621866.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

开始填坑力

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。带路径压缩的并查集的时间复杂度已被证明是 \(O(\alpha(n))\) 的。这个函数的值在当 \(n\) 实际有意义的范围内不会大于 \(4\)

但是对于多组关系,普通的并查集就难以维护了。

这个时候就可以使用 扩展域并查集

扩展域并查集

扩展域并查集常用来维护多组关系的集合合并问题,在实现上比带权并查集要简单一些 (个人觉得)

主要思想

其实很简单,将一个点拆分成多个点,在不同的关系中使用,维护多个关系。

代码实现时,可以通过的对点的序号 \(+\) 点的总个数来实现拆点操作。

下面看例题:

实际应用

NOIp提高组2010:关押罪犯

题目描述

\(S\) 城现有两座监狱,一共关押着 \(N\) 名罪犯,编号分别为 \(1- N\)

他们之间的关系自然也极不和谐。

很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。

我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。

如果两名怨气值为 \(c\) 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为 \(c\) 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力 从大到小 排成一个列表,然后上报到 \(S\)\(Z\) 市长那里。

公务繁忙的 \(Z\) 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。

在详细考察了 \(N\) 名罪犯间的矛盾关系后,警察局长觉得压力巨大。

他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。

假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。那么, 应如何分配罪犯,才能使 \(Z\) 市长看到的那个冲突事件的影响力最小?这个最小值是多少?

输入格式

第一行为两个正整数 \(N\)\(M\) ,分别表示罪犯的数目以及存在仇恨的罪犯对数。

接下来的 \(M\) 行每行为三个正整数 \(a_j,b_j,c_j\) ,表示 \(a_j\) 号和 \(b_j\) 号罪犯之间存在仇恨,其怨气值为 \(c_j\)

数据保证 \(1≤aj<bj<N,0<cj≤1000000000\) 且每对罪犯组合只出现一次。

输出格式

输出共 \(1\) 行,为 \(Z\) 市长看到的那个冲突事件的影响力。

如果本年内监狱中未发生任何冲突事件,请输出 \(0\)

数据范围

\(N\leq 20000,M \leq 100000,\ 1≤aj<bj<N,\ 0<cj≤1000000000\)

样例

in:

out:

例题解析:

题目求最大影响的最小值,由贪心我们可以可以知道,我们要尽量不让更大的冲突发生,考虑排序,先保证让大的冲突不发生。

若是只有一个监狱,那就直接使用一个普通并查集,维护就好。然而此题有两个监狱,一个人放在这个监狱,另一个人必定放在另外一个监狱里面。

我们可以考虑把第 \(i\) 个人拆成 \(i\)\(i+1\) 。一个维护友好的集合,一个维护对立的集合。每次查询一个关系,两人应该分别在两个集合中,若查询到两个人在同一集合,则这个事件无法避免的会发生。

放code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=1000010;

struct iee
{
	int x,y;
	ll k;
} rela[N];
bool cmp(iee a,iee b)
{
	return a.k>b.k;
}

int n,m;
int parent[N];
void init();
int find(int x);
int union_(int x,int y);
int check(int x,int y);

int main()
{
	init();
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
		scanf("%d%d%lld",&rela[i].x,&rela[i].y,&rela[i].k);
	sort(rela+1,rela+1+m,cmp);
	for(int i=1;i<=m;i++)
	{
		if(check(rela[i].x,rela[i].y))
		{
			cout<<rela[i].k;
			exit(0);//贪心,若在同一集合直接输出并退出
		}
		else
		{
			union_(rela[i].x+n,rela[i].y);
			union_(rela[i].x,rela[i].y+n);//扩展域并查集核心:x + n
		}
	}
	cout<<0;
	return 0;
}

void init()
{
	for(int i=0;i<N;i++)
		parent[i]=i;
}

int find(int x)
{
	int x_root=x;
	while(x_root!=parent[x_root])
	{
		x_root=parent[x_root];
	}
	while(x!=x_root)
	{
		int tmp=parent[x];
		parent[x]=x_root;
		x=tmp;
	}
	return x_root;
}

int union_(int x,int y)
{
	int x_root=find(x);
	int y_root=find(y);
	if(x_root==y_root) return 0;//合并失败
	parent[x_root]=y_root;
	return 1;
}

int check(int x,int y)
{
	return find(x)==find(y);
}

Recommend

  • 32
    • www.tuicool.com 4 years ago
    • Cache

    详解并查集

    详解并查集 Powered by WSY in SSF 2019-11-02  13:46 【1】并查集的定义:   并查集(Disjoint  Set)是一种非常精巧的非常实用的数据结构,它主要用来处理一些不相交集合...

  • 25
    • 微信 mp.weixin.qq.com 4 years ago
    • Cache

    Union-Find 并查集算法详解

    预计阅读时间: 10  分钟 今天讲讲 Union-Find 算法,也就是常说的并查集算法,主要是解决图论中「动态连通性」问题的。名词很高端,其实特别好理解,等会解释,另外这个...

  • 17
    • www.cnblogs.com 4 years ago
    • Cache

    acwing 239. 奇偶游戏 并查集

    地址 https://www.acwing.com/problem/content/241/ 小A和小B在玩一个游戏。 首先,小A写了一个由0和1组成的序列S,长度为N。 然后,小B向小A提出...

  • 28

    【并查集】一种与时间赛跑的巧妙算法 引入:(NOIP模拟题)极端寒冬 (不要求刚刚接触并查集的读者完全明白本题) 先了解一下并查集是个什么东西: 合并两点所在集合和 查找两点是否...

  • 6

    Armin's BlogVIJOS-P1045 Kerry的电缆网络(并查集)February 24, 2016题目链接 按照长度排序,然后并查集即可。 #include<cstring> #incl...

  • 3

    Armin's BlogPOJ 1611 The Suspects(并查集)November 28, 2015题目链接 题意:非典时期,共有 n 个人(标号 0~n-1),分成 m 组。第一行输入 n(0...

  • 6

    Armin's BlogPOJ 2524 Ubiquitous Religions(并查集)November 29, 2015题目链接 题意:调查学校的学生宗教信仰情况,第一行输入 n(总人数)和 m,...

  • 7

    Armin's BlogHDU 1232 畅通工程(并查集)November 30, 2015题目链接 中文题,最简单的并查集。午休时间怒 A 一发~ #inclu...

  • 5
    • arminli.com 3 years ago
    • Cache

    HDU 4496 D-City(并查集)

    HDU 4496 D-City(并查集)November 27, 2015题目链接 题意:第一行输入 N(0 < N <= 10000 )和 M(0 < M <= 100000 )分别代表节点数和边数,接下来 M 行...

  • 7

    Armin's BlogHDU1213 How Many Tables(并查集)March 30, 2016题目链接 题意:n 个人,如果 a 和 b 认识,b 和 c 认识,那么认为 a...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK