poj_1182 并查集
题目大意
动物王国中有三类动物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),输出假话的总数。
题目分析
由于给出X和Y的相对关系,并不能确定X和Y分别是哪种动物,因此没法将动物i属于A、B、C中的哪一类作为一个集合。但是,题目是典型的集合操作,判断两个元素是否符合某种关系,因此仍然考虑使用并查集来解决。
使用并查集这种结构时候,需要维护相关的数据信息。考虑每两个动物只要能够确定相互关系,则将他们加入一个集合,对于集合中的每个动物,我们维持
该动物和该集合的根节点动物的相对关系。在每次获得两个动物X和Y的相对关系的时候,对于之前已经知道的那些和X或Y相关的动物的关系,只需要知道这些动
物和该共同集合的根节点动物的相对关系,则可以确定他们之间的相对关系。
在每次得到X和Y之间的关系rel时,先获得他们的根节点,如果根节点p相同,则可以通过X和p的关系,Y和p的关系,确定X和Y在之前就可以确
定的关系rel_1。将rel_1和本次输入的X和Y之间的关系rel进行对比,如果不同,则说明出错;如果根节点不同,分别为px,
py,则将px和py合并,然后根据X和px的关系,X和Y的关系,y和py的关系,得到px和py的关系。
关于带权并查集
带权并查集和普通并查集最大的区别在于带权并查集合并的是可以推算关系的点的集合(可以通过集合中的一个已知值推算这个集合中其他元素的值)。而一般并查集合并的意图在于这个元素属于这个集合。带权并查集相当于把“属于”的定义拓展了一下,拓展为有关系的集合。
实现(c++)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define MAX_ANIMAL_NUM 50010
int gPar[MAX_ANIMAL_NUM]; //集合的根节点
int gRel[MAX_ANIMAL_NUM]; //节点和所属集合的根节点之间的关系 //gRel[i] == 0, i 和它的最老祖先是同类动物
//gRel[i] == 1, i 吃它的最老祖先
//gRel[i] == 2, i 的最老祖先吃它
void Init(int n){
for (int i = 1; i <= n; i++){
gPar[i] = i;
gRel[i] = 0;
}
} //获得集合的根节点,同时维护信息,主要是更新 节点到跟节点的关系数组 gRel[x]
int GetPar(int c){
if (c != gPar[c]){
int p = gPar[c]; //c还没被进行路径压缩前,节点c所属集合的根节点 p
gPar[c] = GetPar(gPar[c]); //进行路径压缩,路径压缩之后,递归函数返回时,p已经设置了根节点,同时也设置了p和总集合的根节点的关系
gRel[c] = (gRel[c] + gRel[p]) % 3; //根据c和p的关系,以及p和总集合的根节点的关系,设置c和总集合的根节点的关系
}
return gPar[c];
} int main(){
int N, K;
scanf("%d %d", &N, &K);
int rel, x, y;
int error_count = 0;
Init(N);
for (int i = 0; i < K; i++){
scanf("%d %d %d", &rel, &x, &y);
if (x > N || y > N){
error_count++;
continue;
}
rel--;
int p1 = GetPar(x), p2 = GetPar(y);
if (p1 == p2){
if ((gRel[x] + 3 - gRel[y]) % 3 != rel){ //关系不一致
error_count++;
}
}
else{ //对集合进行合并,同时需要注意,根据 x-->p1, x->y, y->p2的关系,得到 p1->p2的关系
gPar[p1] = p2;
gRel[p1] = (3 - gRel[x] + rel + gRel[y]) % 3;
}
}
printf("%d\n", error_count);
return 0;
}
poj_1182 并查集的更多相关文章
- BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]
4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...
- 关押罪犯 and 食物链(并查集)
题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值"( ...
- 图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用
图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 ...
- bzoj1854--并查集
这题有一种神奇的并查集做法. 将每种属性作为一个点,每种装备作为一条边,则可以得到如下结论: 1.如果一个有n个点的连通块有n-1条边,则我们可以满足这个连通块的n-1个点. 2.如果一个有n个点的连 ...
- [bzoj3673][可持久化并查集 by zky] (rope(可持久化数组)+并查集=可持久化并查集)
Description n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0& ...
- [bzoj3123][sdoi2013森林] (树上主席树+lca+并查集启发式合并+暴力重构森林)
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集
3673: 可持久化并查集 by zky Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 1878 Solved: 846[Submit][Status ...
- Codeforces 731C Socks 并查集
题目:http://codeforces.com/contest/731/problem/C 思路:并查集处理出哪几堆袜子是同一颜色的,对于每堆袜子求出出现最多颜色的次数,用这堆袜子的数目减去该值即为 ...
- “玲珑杯”ACM比赛 Round #7 B -- Capture(并查集+优先队列)
题意:初始时有个首都1,有n个操作 +V表示有一个新的城市连接到了V号城市 -V表示V号城市断开了连接,同时V的子城市也会断开连接 每次输出在每次操作后到首都1距离最远的城市编号,多个距离相同输出编号 ...
随机推荐
- 【Unity笔记】常用的优化小技巧
一.当通过GetComponent获取一个组件时,不在Update中每帧进行查找,可在Start中查找一次并用一个私有变量去保存这个组件. public class Test : MonoBehavi ...
- Java 加载配置文件的方式
一 使用原生方式读取配置文件 1 文件系统加载 Java代码 InputStream in = new FileInputStream("config.properties") ...
- mount -t nfs 不能使用
去年使用一个新的文件系统的时候,发现mount -t nfs ip:/g/ftp ~/mnt -o tcp,nolock 不能使用 一直以为是因为mount 命令更新了,有些用法我不会用,但是刚才发现 ...
- C++中声明与定义的区别
如果是指变量的声明和定义: 从编译原理上来说,声明是仅仅告诉编译器,有个某类型的变量会被使用,但是编译器并不会为它分配任何内存.而 定义就是分配了内存.对于下面的两句代码:void Func(){in ...
- 轻量级ORM框架Dapper应用二:使用Dapper实现CURD操作
在上一篇文章中,讲解了如何安装Dapper,这篇文章中将会讲解如何使用Dapper使用CURD操作. 例子中使用到的实体类定义如下: using System; using System.Collec ...
- DataGridView使用技巧三:不显示最下面的新行、判断新增行
一.DataGridView不显示下面的新行 通常DataGridView的最下面一行是用户新追加的行(行头显示*).如果不想让用户新追加行即不想显示该新行,可以将DataGridView对象的All ...
- 【转】nginx中proxy_set_header Host $host的作用
nginx为了实现反向代理的需求而增加了一个ngx_http_proxy_module模块.其中proxy_set_header指令就是该模块需要读取的配置文件.在这里,所有设置的值的含义和http请 ...
- 【Java面试题】50 垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?
1.对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址.大小以及使用情况. 通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象.通过这种方式确定哪些对象是"可达的&q ...
- SharePoint 沙盒无法启动新的解决方案服务的SPUserCodeV4
开发部署时报错: 错误原因:没有启动该服务: 解决方式:打开管理中心—应用程序管理—服务应用程序--管理服务器上的服务,启动该服务即可.
- SQL Server 删除数据库所有表和所有存储过程
场景: SQL Server中,需要删除所有表或所有存储过程时,手动的方式只能逐个进行删除,耗个人时间,所以想弄个语句来实现这样的需求. 如果由于外键约束删除table失败,则先删除所有约束: - ...