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. unity, access standard shared emission by script

    unity 5.1.1f1 personal 用下面方法在脚本中设置standard shader的emssion: gameObject.GetComponent<MeshRenderer&g ...

  2. ML中Boosting和Bagging的比較

    说到ML中Boosting和Bagging,他们属于的是ML中的集成学习,集成学习法(Ensemble Learning) ①  将多个分类方法聚集在一起.以提高分类的准确率. (这些算法能够是不同的 ...

  3. [css]后台管理系统布局

    知识点: 绝对定位+overflowhidden 整体思路 三大块 pg-header---需要固定 (height:48px) pg-content menu 右侧菜单-需要固定(width:200 ...

  4. makefile之call函数

    call函数是唯一一个可以创建定制化参数函数的引用函数. 支持对自定义函数的引用; 支持将一个变量定义为一个复杂的表达式,用call函数根据不同的参数对它进行展开来获取不同的结果; 函数语法: $(c ...

  5. 基于libmemcached,php扩展memcached的安装

    基于libmemcached,php扩展memcached的安装 张映 发表于 -- 分类目录: php 标签:libmemcached, memcached, php, 安装 一,为什么要装memc ...

  6. 本地测试Tomcat配置Https访问

    一.tomcat开启HTTPS配置 1) 准备证书 使用jdk工具keytool生成一个ssl测试用证书, 一路按照提示操作输入即可 keytool -genkey -alias tomcat -ke ...

  7. Errors occurred while updating the change sets for SVNStatusSubscriber org.apache.subversion.javahl.

    原因:eclipse-svn插件版本过低,导致不能识别svn客户端中的代码,从而报错 解决方法: 1.点击“Help”下拉菜单中的“Eclipse Marketplace”, 2.在弹出的窗口中,点击 ...

  8. linux学习笔记10---命令nl

    nl命令在linux系统中用来计算文件中行号.nl 可以将输出的文件内容自动的加上行号! nl命令读取 file 参数(缺省情况下标准输入),计算输入中的行号,将计算过的行号写入标准输出.在输出中,n ...

  9. Quotations中页面弹出的问题

  10. Hadoop中的RPC机制

    1.  RPC——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据.在OSI ...