POJ1182

http://poj.org/problem?id=1182

题目

难得的中文题。。。

食物链

Time Limit: 1000MS Memory Limit: 10000K

Total Submissions: 56252 Accepted: 16485

Description

动物王国中有三类动物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),输出假话的总数。

Input

第一行是两个整数N和K,以一个空格分隔。

以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。

若D=1,则表示X和Y是同类。

若D=2,则表示X吃Y。

Output

只有一个整数,表示假话的数目。

Sample Input

100 7

1 101 1

2 1 2

2 2 3

2 3 3

1 1 3

2 3 1

1 5 5

Sample Output

3

思路

对于每只动物i创建3个元素i-A,i-B,i-C,并用3×N个元素建立并查集,维护如下信息:

  • i-X表示i属于X
  • 如果i-A和j-B在同一个组里,那么如果i属于A,j就一定属于B。如果j属于B,i就一定属于A。

我们对每条信息进行如下操作:

  • 如果x或者y比N大或者小于1,则答案+1
  • x和y属于同一种类。如果已知x和y不属于同一类,则答案+1。否则合并x-A和y-A、x-B和y-B、x-C和y-C
  • x吃y。如果已知x和y属于同一类或者x-A和y-C在同一个集合,则答案+1。否则合并x-A和y-B、x-B和y-C、x-C和y-A

最后,输出答案。

需要注意的是一定要有路径压缩,即使用rank平衡各树的长度,否则很有可能超时。

还有一种解法是带权并查集,参见http://blog.csdn.net/balloons2012/article/details/7871104

代码

Source Code

Problem: 1182       User: liangrx06
Memory: 1368K Time: 266MS
Language: C++ Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
using namespace std; const int N = 50000; int n;
int pre[3*N+1];
int rank[3*N+1]; void init()
{
for (int i = 1; i <= 3*n; i ++) {
pre[i] = i;
rank[i] = 0;
}
} int find(int a)
{
while (a != pre[a])
a = pre[a];
return a;
} void unite(int a, int b)
{
a = find(a);
b = find(b);
if (a == b) return;
if (rank[a] < rank[b]) {
pre[a] = b;
} else {
pre[b] = a;
if (rank[a] == rank[b])
rank[a] ++;
}
} bool same(int a, int b)
{
return find(a) == find(b);
} int main(void)
{
int k;
int d, a, b;
int res = 0; cin >> n >> k;
init();
while ( k-- ) {
scanf("%d%d%d", &d, &a, &b);
if ( a > n || b > n ) {
res ++;
}
else if ( d == 1 ) {
if ( same(a, b+n) || same(a, b+2*n) ) {
res ++;
} else {
unite(a, b);
unite(a+n, b+n);
unite(a+2*n, b+2*n);
}
}
else {
if ( same(a, b) || same(a, b+2*n) ) {
res ++;
} else {
unite(a, b+n);
unite(a+n, b+2*n);
unite(a+2*n, b);
}
}
}
printf("%d\n", res); return 0;
}

POJ2236

http://poj.org/problem?id=2236

题意

一张图上分布着n台坏了的电脑,并知道它们的坐标。两台修好的电脑如果距离<=d就可以联网,也可以通过其他修好的电脑间接相连。给出操作“O x”表示修好x,给出操作“S x y”,请你判断x和y在此时有没有连接上。

思路

基本并查集题目,每次O x都对所有与x相连的电脑做更新,加入并查集,S x y时直接判断是否相连即可。

我的代码是书中所给并查集的标准实现。

代码

Source Code

Problem: 2236       User: liangrx06
Memory: 296K Time: 1500MS
Language: C++ Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <set>
#include <string>
#include <cmath>
using namespace std; const int N = 1001; struct Node {
int x, y;
}; int n, d;
Node node[N+1];
int pre[N+1];
int rank[N+1]; void init()
{
for (int i = 1; i <= n; i ++) {
pre[i] = i;
rank[i] = 0;
}
} int find(int a)
{
while (a != pre[a])
a = pre[a];
return a;
} void unite(int a, int b)
{
a = find(a);
b = find(b);
if (a == b) return;
if (rank[a] < rank[b]) {
pre[a] = b;
} else {
pre[b] = a;
if (rank[a] == rank[b])
rank[a] ++;
}
} bool same(int a, int b)
{
return find(a) == find(b);
} void input()
{
cin >> n >> d;
for (int i = 1; i <= n; i ++) {
scanf("%d%d", &node[i].x, &node[i].y);
}
} double dis(int a, int b)
{
int x2 = (node[a].x-node[b].x) * (node[a].x - node[b].x);
int y2 = (node[a].y-node[b].y) * (node[a].y - node[b].y);
return sqrt((double)(x2 + y2));
} void solve()
{
string s;
int a, b;
set<int> rep; while ( cin >> s ) {
if (s == "O") {
scanf("%d", &a);
if ( rep.find(a) == rep.end() ) {
set<int>::iterator it;
for (it = rep.begin(); it != rep.end(); it ++) {
if ( dis(a, *it) <= d ) {
//printf("unite %d %d\n", a, *it);
unite(a, *it);
}
}
rep.insert(a);
}
} else {
scanf("%d%d", &a, &b);
//printf("%d %d %d %d\n", a, b, find(a), find(b));
if ( same(a, b) )
printf("SUCCESS\n");
else
printf("FAIL\n");
}
}
} int main(void)
{
input();
init();
solve(); return 0;
}

POJ1703

http://poj.org/problem?id=1703

题意

在这个城市里有两个黑帮团伙,现在给出N个人,问任意两个人他们是否在同一个团伙。

输入D x y代表x于y不在一个团伙里。

输入A x y要输出x与y是否在同一团伙或者不确定他们在同一个团伙里。

思路

这个题是poj1182的简单版,具体不再赘述。

代码

Source Code

Problem: 1703       User: liangrx06
Memory: 1772K Time: 344MS
Language: C++ Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
using namespace std; const int N = 100000; int n;
int pre[2*N+1];
int rank[2*N+1]; void init()
{
for (int i = 1; i <= 2*n; i ++) {
pre[i] = i;
rank[i] = 0;
}
} int find(int a)
{
while (a != pre[a])
a = pre[a];
return a;
} void unite(int a, int b)
{
a = find(a);
b = find(b);
if (a == b) return;
if (rank[a] < rank[b]) {
pre[a] = b;
} else {
pre[b] = a;
if (rank[a] == rank[b])
rank[a] ++;
}
} bool same(int a, int b)
{
return find(a) == find(b);
} int main(void)
{
int t, m;
char s[2];
int a, b; cin >> t;
while ( t-- ) {
cin >> n >> m;
init();
while ( m-- ) {
scanf("%s%d%d", s, &a, &b);;
if ( s[0] == 'D' ) {
unite(a, b+n);
unite(a+n, b);
} else {
if ( same(a, b) )
printf("In the same gang.\n");
else if ( same(a, b+n) )
printf("In different gangs.\n");
else
printf("Not sure yet.\n");
}
}
} return 0;
}

AOJ2170

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2170

题意

给定一棵树,对于这棵树有两个操作,M i表示将i的所有子孙节点以i为树根从原树中分离出来,Q i表示询问节点i的树根是多少。

思路

用数组pre[i]记录节点i的父亲节点,若i是根节点就记为i,这个题中1是根节点。

这样对于两种操作我们只要如下处理即可:

  • M i:将tree[i]改为它本身,也就是i
  • Q i:从i向上查找直到找到它的根节点

代码

#include <iostream>
#include <cstdio>
using namespace std; const int N = 100000; int n, p;
int pre[N+1]; int find(int x)
{
while (x != pre[x])
x = pre[x];
return x;
} int main(void)
{
while (scanf("%d%d", &n, &p) != EOF) {
if (!n && !p) break;
pre[1] = 1;
for (int i = 2; i <= n; i ++)
scanf("%d", &pre[i]);
long long sum = 0;
for (int i = 1; i <= p; i ++) {
char s[2];
int x;
scanf("%s%d", s, &x);
if (s[0] == 'M')
pre[x] = x;
else
sum += find(x);
}
printf("%lld\n", sum);
} return 0;
}

《挑战程序设计竞赛》2.4 数据结构-并查集 POJ1182 2236 1703 AOJ2170的更多相关文章

  1. HDU 5923 Prediction(2016 CCPC东北地区大学生程序设计竞赛 Problem B,并查集)

    题目链接  2016 CCPC东北地区大学生程序设计竞赛 B题 题意  给定一个无向图和一棵树,树上的每个结点对应无向图中的一条边,现在给出$q$个询问, 每次选定树中的一个点集,然后真正被选上的是这 ...

  2. POJ 2386 Lake Counting 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=2386 <挑战程序设计竞赛>习题 题目描述Description Due to recent rains, water has ...

  3. Aizu 2249Road Construction 单源最短路变形《挑战程序设计竞赛》模板题

    King Mercer is the king of ACM kingdom. There are one capital and some cities in his kingdom. Amazin ...

  4. 《挑战程序设计竞赛》2.3 动态规划-优化递推 POJ1742 3046 3181

    POJ1742 http://poj.org/problem?id=1742 题意 有n种面额的硬币,面额个数分别为Ai.Ci,求最多能搭配出几种不超过m的金额? 思路 据说这是传说中的男人8题呢,对 ...

  5. 挑战程序设计竞赛》P345 观看计划

                                                 <挑战程序设计竞赛>P345 观看计划 题意:一周一共有M个单位的时间.一共有N部动画在每周si时 ...

  6. 算法手记 之 数据结构(并查集详解)(POJ1703)

    <ACM/ICPC算法训练教程>读书笔记-这一次补上并查集的部分.将对并查集的思想进行详细阐述,并附上本人AC掉POJ1703的Code. 在一些有N个元素的集合应用问题中,通常会将每个元 ...

  7. ACM数据结构-并查集

    ACM数据结构-并查集   并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合 ...

  8. 种类并查集——带权并查集——POJ1182;HDU3038

    POJ1182 HDU3038 这两个题比较像(一类题目),属于带权(种类)并查集 poj1182描绘得三种动物种类的关系,按照他一开始给你的关系,优化你的种类关系网络,最后看看再优化的过程中有几处矛 ...

  9. poj 1182 食物链 并查集 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=1182 题解 可以考虑使用并查集解决 但是并不是简单的记录是否同一组的这般使用 每个动物都有三个并查集 自己 天敌 捕食 并查集 那么在获得 ...

随机推荐

  1. Cocos2d-X中的ZORDER和Tag

    ZORDER:是描写叙述渲染顺序的值,每一个CCNode都有ZORDER,默认是0 ZORDER越大,越后面绘制 假设ZORDER同样.那么看arrival顺序.先增加的节点先绘制 ZORDER仅仅在 ...

  2. 将Cmder添加到系统右键菜单中

    1.把 Cmder 加到环境变量 把Cmder.exe存放的目录添加到系统环境变量: 加完之后,Win+r一下输入cmder,即可. 2.添加 cmder 到右键菜单:环境变量添加后,在任意文件夹中即 ...

  3. 远程调试 Weinre

    什么是远程调试? 说白了,就是可以通过PC端[F12开发者工具]查看并调试移动端的页面内容,如html.css.js.Network资源等. 重要的事情说三遍:weinre所占有的端口不需要和监听页面 ...

  4. blender, fbx导入blender进行编辑

    fbx文件导入blender后,直接点下面Object Mode弹不出下拉菜单,从而无法进入Edit Mode.解法是先点一下右边Scene层级列表中的Sphere节点,将其选中,然后再点下面的Obj ...

  5. Java并发编程(四):线程安全性

    一.定义 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的. 二.线程安 ...

  6. 环境搭建基础知识2(sublime text3中配置verilog语法高亮)

    需求说明:Verilog设计 内容       :verilog开发环境搭建 来自       :时间的诗 1 软件下载 1.1 官方下载 地址http://www.sublimetext.com/3 ...

  7. 真正理解红黑树,真正的(Linux内核里大量用到的数据结构,且常被二货问到)

    作为一种数据结构.红黑树可谓不算朴素.由于各种宣传让它过于神奇,网上搜罗了一大堆的关于红黑树的文章,不外乎千篇一律,介绍概念,分析性能,贴上代码,然后给上罪恶的一句话.它最坏情况怎么怎么地...    ...

  8. 折腾gcc/g++链接时.o文件及库的顺序问题(转)

    转自: http://www.cnblogs.com/OCaml/archive/2012/06/18/2554086.html#sec-1-1 折腾gcc/g++链接时.o文件及库的顺序问题 Tab ...

  9. 使用thrift进行跨语言调用(php c# java)

    使用thrift进行跨语言调用(php c# java)   1:前言 实际上本文说的是跨进程的异构语言调用,举个简单的例子就是利用PHP写的代码去调C#或是java写的服务端.其实除了本文提供的办法 ...

  10. xgboost 安装

    git clone --recursive https://github.com/dmlc/xgboostcd xgboost/make -j4 cd python-package/ python s ...