并查集

Luogu P2661 信息传递

大憨熊 提交于 2019-11-29 08:30:15
Luogu P2661 信息传递 并查集+判环。(这样做甚至能做成在线的,极限复杂度就只有 \(O(n^2)\) ) 我们在连接一个点到另一个点之前,先用并查集判断是否构成一个环,如果是的话,我们就可以记录下这个答案,然后维护最小的答案。 那么,如果构成一个环的话,怎么记录它的长度呢? 我们可以先定义一个变量 \(cnt\) ,在并查集获取祖先的函数中使 \(cnt\) 的值加 \(1\) ,最后函数结束时就能得到这个环的长度了。 还有一点,如果构成了一个环,那就不要把环的结尾连上,否则会死循环。 #include<bits/stdc++.h> #define N 200010 #define INF 0x3f3f3f3f using namespace std; int n,ans=INF,cnt; int fa[N]; void Init() { for(int i=1;i<=n;i++) { fa[i]=i; } return; } int Find(int x) { cnt++; return fa[x]==x?x:Find(fa[x]); } int main() { scanf("%d",&n); Init(); for(int i=1;i<=n;i++) { cnt=0; int t; scanf("%d",&t); if(Find(t)==i) { ans=min

雷神领域(并查集真是个好东西)并查集+流氓dp

醉酒当歌 提交于 2019-11-29 04:46:47
考场上,整整看了半个小时以上的题目!!! 化简题意 : 给定一个全0矩阵,一些坐标点(x,y)为1,当三个点可以构成一个直角三角形时(直角边长为整数)拓展为一个矩形,之后从(0,0)出发,求最多的占用行数或占用列数 反正就是很麻烦的题就对了。。。 考场历程: 1、没看懂题,就去看下一题了 2、第三题可做性极差(tpsort+dp或网络流) 3、n^2拓展完了新点,发现样例就是个弟弟!(拓展完变成全1矩阵) 4、最小最大,想着二分来着,但是秒pass 5、想强行建边,跑最短路 6、dp根本想不出来....(行和列) 7、考完之后发现这题就是在侮辱智商 solution: 首先,n^2拓展点很容易,枚举点如何暴力即可。 先来讲dp怎么写吧..... 这个dp就是流氓..... 怎么说呢,考场上一直在想:跑一个行最优,列最优,比最小值,就成了最长不下降子序列之类的东西... 但是路径不一定是一个嘢.... 于是考场就暴毙了 其实,dp方程式.... 二维,f[i][j]表示从(0,0)拓展到当前点的最大值 如果当前点是1点,+1 如果不是,就更新,从左边和上边找一个最大值续上 我管你是行最大还是列最大,都给我最大然后+1再说 这就是这个dp欠的地方(还是我太弱了) dp的事解决了,加上之前的n^2拓展点,理论上5000*5000应该是能过去的,但是25000000,加上3~4的常数

最小生成树

耗尽温柔 提交于 2019-11-29 04:12:48
一、概念 在一个连通图的所有生成树中,各边的代价之和最小的那棵生成树称为该连通网的最小代价生成树,简称最小生成树。 二、构建最小生成树的方法 1.普利姆算法 首先,我们假设有一棵只包含一个顶点v(v可为图中的任意一点)的树T。然后贪心地选取T和其他顶点之间相连的最小权值的边,并把它加到T中。 不断进行这个操作,就可以得到一棵生成树了。 以此图为例 初始先将V1(随便一个都可以,这里以V1举例)加入到最小生成树,则得到信息表为如下: 最小生成树中只有V1一个点,最小生成树到各点的距离如图所示。下一步添加最小的边,因为v1已经在最小生成树中,所以添加v3。 更新此表。 则此时最小权值为4,添加v6。以此类推,添加所有的点到最小生成树。 代码: int cost[maxv][maxv];//cost[u][v]表示边e=(u,v)的权值(不存在的情况为inf), int mincost[maxv];//从最小生成树出发的边到每个顶点的最小权重 bool used[maxv];//顶点i是否包含在最小生成树中 int V;//顶点数 int prim() { for(int i=0;i<V;i++) { mincost[i] = inf;//inf的值是比最大权值边的值还要大的一个数 used[i] = false; } mincost[0] = 0;//先添加的是第0个点 int res

[NOIP2010]关押罪犯(并查集)

风格不统一 提交于 2019-11-29 02:18:13
题目描述 S 城现有两座监狱,一共关押着 N 名罪犯,编号分别为 1−N 。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为 c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为 c 的冲突事件。 每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。 在详细考察了 N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。 那么,应如何分配罪犯,才能使Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少? 输入输出样例 输入 #1 复制 4 6 1 4 2534 2 3 3512 1 2 28351 1 3 6618 2 4 1805 3 4 12884 输出 #1 复制 3512 说明/提示 【输入输出样例说明】罪犯之间的怨气值如下面左图所示,右图所示为罪犯的分配方法,市长看到的冲突事件影响力是

[NOI2001]食物链(并查集)

久未见 提交于 2019-11-29 02:03:45
题目描述 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形。A 吃 B,B 吃 C,C 吃 A。 现有 N 个动物,以 1 - N 编号。每个动物都是 A,B,C 中的一种,但是我们并不知道 它到底是哪一种。 有人用两种说法对这 N 个动物所构成的食物链关系进行描述: 第一种说法是“1 X Y”,表示 X 和 Y 是同类。 第二种说法是“2 X Y”,表示 X 吃 Y 。 此人对 N 个动物,用上述两种说法,一句接一句地说出 K 句话,这 K 句话有的是真 的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 • 当前的话与前面的某些真的话冲突,就是假话 • 当前的话中 X 或 Y 比 N 大,就是假话 • 当前的话表示 X 吃 X,就是假话 你的任务是根据给定的 N 和 K 句话,输出假话的总数。 输入格式 从 eat.in 中输入数据 第一行两个整数,N,K,表示有 N 个动物,K 句话。 第二行开始每行一句话(按照题目要求,见样例) 输出格式 输出到 eat.out 中 一行,一个整数,表示假话的总数。 输入输出样例 输入 #1 复制 100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5 输出 #1 复制 3 说明/提示 1 ≤ N ≤ 5 ∗ 10^4 1 ≤ K ≤ 10^5 多种解法

学术交流(并查集)

北战南征 提交于 2019-11-29 01:41:42
【问题】 【思路】 由于题目是让求出需要翻译机的个数,一共有m个人,并且每个人可能一种语言都不会,也有可能会多种语言!因此,一个很通用的思路我们将可以互相交流的放到一个集合中,最终如果形成n个集合,那么就需要n-1个翻译机! 说到集合的多次合并问题,不得不提一个高效且很容易实现的结构,并查集!并查集的理论首先对一些数据进行初始化节点,使用father_map和size_map表示,初始化时节点的父节点为其本身,我们也叫作代表节点! 合并两个集合时,我们需要判断其代表节点是否相同以及大小,如果相同,属于统一集合,直接return, 否则,将小的集合的代表节点直接挂在大集合的节点上,完成合并! 但是,其真正高效的原因是由于查找操作造成的, 其查找代表节点的同时,会将其上方的节点全部挂在代表节点上,下次查询时间都为O(1)了! 这也是并查集为什么进行多次合并都很高效的主要原因! 针对于本题,主要分为五个步骤: 1. 首先统计每种语言所会的人,count=n(人数),并对每个人建立并查集初始化! 2. 遍历每个语言,将这每个语言对应的人所在的集合进行合并! 3. 每次合并count都要减一, 也就是需要翻译机的个数减一! 4. 所有合并结束后,最后孤立无法交流的集合数为count 5. 因此需要count-1个翻译机 #include <unordered_map> #include

超有爱的并查集[转]

佐手、 提交于 2019-11-29 00:05:47
例子就是杭电上的畅通工程: http://acm.hdu.edu.cn/showproblem.php?pid=1232 首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性问题。比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块。像畅通工程这题,问还需要修几条路,实质就是求有几个连通分支。 如果是1个连通分支,说明整幅图上的点都连起来了,不用再修路了;如果是2个连通分支,则只要再修1条路,从两个分支中各选一个点,把它们连起来,那么所有的点都是连起来的了;如果是3个连通分支,则只要再修两条路…… 以下面这组数据输入数据来说明 4 2 1 3 4 3 第一行告诉你,一共有4个点,2条路。下面两行告诉你,1、3之间有条路,4、3之间有条路。那么整幅图就被分成了1-3-4和2两部分。只要再加一条路,把2和其他任意一个点连起来,畅通工程就实现了,那么这个这组数据的输出结果就是1。好了,现在编程实现这个功能吧,城镇有几百个,路有不知道多少条,而且可能有回路。 这可如何是好? 我以前也不会呀,自从用了并查集之后,嗨,效果还真好!我们全家都用它! 并查集由一个整数型的数组和两个函数构成。数组pre[]记录了每个点的前导点是什么,函数find是查找,join是合并。 int

8.29 活着的意义

纵饮孤独 提交于 2019-11-28 22:51:52
题意 给一张 \(n\) 个点 \(m\) 条边的无向图,有一个对于这个无向图的操作,即去除图中的一个生成森林(即所有连通块中生成树的集合)。不断对该无向图进行操作直到该图中的边全部被删除。对于每一条边,输出他是在第几次被删除的。 如果有多种方案,输出其中一种即可 解法 首先我们有一个很好想的 \(O(MN)\) 暴力 遍历每一条边,每次进行生成树操作:具体来说,就是每次开一个并查集,如果该边的两个端点不在同一个连通块中,则把它们联通,并且把该边从边集中删除;否则跳过该边 考虑我们如何对暴力算法进行优化 如果我们开若干个并查集,每次对于一条边,如果在 \(1\) 号并查集中它的两端所连接的点在一个连通块内,我们就在 \(2\) 号并查集中进行插入,以此类推... 通过上述算法,我们可以求出每一次操作后形成的生成森林 但是我们会发现,这个算法和原来相比,不仅时间复杂度没有改观,空间复杂度反而变得更劣了 但是这个算法的思想却有一定的启发性 我们可以发现一个性质:对于一条边,如果它可以在第 \(i\) 号并查集中插入,那么它也一定可以在 \(i+1...n\) 号并查集中插入 这个可以用反证法证明,也可以意会理解一下 发现了这个性质以后,我们就可以二分出第一个可以插入的并查集编号了 这样时间复杂度由 \(O(MN)\) 优化到了 \(O(MlogM)\) 但是空间复杂度仍然无法承受

并查集总结

佐手、 提交于 2019-11-28 22:25:59
并查集基本操作: union + find 解法1: 并查集 class Solution { public: /** * @param n: An integer * @param edges: a list of undirected edges * @return: true if it's a valid tree, or false */ bool validTree(int n, vector<vector<int>> &edges) { // write your code here //union find vector<int> parent(n, -1); for(int i=0; i<edges.size(); i++){ //union int p1 = find(edges[i][0], parent); int p2 = find(edges[i][1], parent); if(p1 == p2) return false; //存在环 parent[p2] = p1; } return edges.size() == n-1; //树中若有n个点,则一定有n-1条边 } //find int find(int e, vector<int> p){ if(p[e] == -1) return e; else return p[e] = find(p[e

带权并查集

浪尽此生 提交于 2019-11-28 20:50:15
所谓带权并查集就是,在若干个集合之间需要做到维护一些信息,如相同,或者矛盾。 POJ1182 题意: 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。 有人用两种说法对这N个动物所构成的食物链关系进行描述: “1 X Y”,表示X和Y是同类。 “2 X Y”,表示X吃Y。 此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 1) 当前的话与前面的某些真的话冲突,就是假话; 2) 当前的话中X或Y比N大,就是假话; 3) 当前的话表示X吃X,就是假话。 你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。 解法: 对于每只动物创建3个元素, i-A,i-B,i-C,并用这 3*N 个元素建立并查集,维护如下信息: 1. i-X 表示“ i 属于种类 x” 2. 并查集里的每一个组表示组内所有元素代表的情况都同时发生或者不发生。 如果 i-A 和 j-B 在同一组里,就表示 i 属于种类 A 那么 j 一定属于种类 B。 那么对于每一条信息我们只需要进行: 第一种:x 和 y 是同一种