种类并查集 POJ - 2492 A Bug's life POJ1182 - 食物链
# 种类并查集
POJ -2492
A Bug's Life
Time Limit: 10000MS Memory Limit: 65536K
Total Submissions: 46754 Accepted: 15083
Description
Background
Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature two different genders and that they only interact with bugs of the opposite gender. In his experiment, individual bugs and their interactions were easy to identify, because numbers were printed on their backs.
Problem
Given a list of bug interactions, decide whether the experiment supports his assumption of two genders with no homosexual bugs or if it contains some bug interactions that falsify it.
Input
The first line of the input contains the number of scenarios. Each scenario starts with one line giving the number of bugs (at least one, and up to 2000) and the number of interactions (up to 1000000) separated by a single space. In the following lines, each interaction is given in the form of two distinct bug numbers separated by a single space. Bugs are numbered consecutively starting from one.
Output
The output for every scenario is a line containing "Scenario #i:", where i is the number of the scenario starting at 1, followed by one line saying either "No suspicious bugs found!" if the experiment is consistent with his assumption about the bugs' sexual behavior, or "Suspicious bugs found!" if Professor Hopper's assumption is definitely wrong.
Sample Input
2
3 3
1 2
2 3
1 3
4 2
1 2
3 4
Sample Output
Scenario #1:
Suspicious bugs found!
Scenario #2:
No suspicious bugs found!
Hint
Huge input,scanf is recommended.
Source
TUD Programming Contest 2005, Darmstadt, Germany
题目大意:某位教授在研究一堆虫子,他把虫子分为两种性别,给你他们的交互行为,判断有没有同性恋。样例第一行为测试数据,第二行分别为虫子的个数 \(n\) 和虫子的交互信息 \(m\) ,接下来 \(m\)行 为虫子的交互信息。
种类并查集。
我们开2*n的数组,1 -- n为自己,n + 1 -- 2n 为性别相反的自己。
拿第一个样例来做示范。
输入1 2
也就是说 \(1\) 和 \(2\) 性别不同,即 \(4\) 和 \(2\) 的性别相同,我们把 \(4\) 和 \(2\) 并起来。同理把 \(1\) 和 \(5\) 并起来。
然后输入2 3
也就是说2和3性别不同,即 2 和 6性别相同,3 和 5 性别相同,把 2和6 3和5并起来。
这个时候我们已经得到了2 4 6,1 3 5两个并查集。
最后一个输入1 3,很明显就看到1 和 3 在同一个并查集,所以他们是百合。
#include<stdio.h>
using namespace std;
int f[4001] = {};
int find(int x)//寻找根节点(也许不叫根节点),差不多这个意思
{
int t = x;
while (x != f[x]) x = f[x];
while (t != f[t])
{
int temp = f[t];
f[t] = x;
t = temp;
}
return x;
}
void insert(int x,int y)//并起来
{
int fx = find(x);
int fy = find(y);
if (fx != fy) f[fy] = fx;
}
int main()
{
int p,n,m,count = 0;
scanf("%d",&p);
while (p--)
{
printf("Scenario #%d:\n",++count);
scanf("%d%d",&n,&m);
for (int i = 1;i<=2 * n;i++) f[i] = i;//初始化
bool check = true;
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
if (check)
{
if (find(x) == find(y))//判断两个在不在同一个并查集
{
printf("Suspicious bugs found!\n\n");//注意两个换行。
check = false;
}
else
{
insert(x,y + n);//把性别相同的连起来
insert(y,x + n);//把性别相同的连起来
}
}
}
if (check) printf("No suspicious bugs found!\n\n");
}
}
食物链
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 98400 Accepted: 29779
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
Source
Noi 01
题目大意:中文的自己看,~~ 懒得解释了~~
同样的种类并查集,这次我们开3*n数组。然后1 -- n 存 与自己是同一类的,n+1 -- 2n 存自己的猎物,2n+1 -- 3n存自己的天敌。
我们省去不符合的输入,直接看有用的
2 1 2
1 吃 2,也就是说 1 的猎物 101 和 2 是同一类,把101和2并起来,然后2的天敌 302 和 1 也是同一类,并起来,然后 1 天敌 也就是 2 的猎物 是同一类,把 301 和 102 并起来。
得到并查集
101 2
302 1
301 102
接下去的差不多就不解释了,直接上代码
#include<stdio.h>
int f[160000] = {};
int find(int x)//寻找根节点
{
int t = x;
while (x != f[x]) x = f[x];
while (t != f[t])
{
int temp = f[t];
f[t] = x;
t = temp;
}
return x;
}
void insert(int x,int y)//并起来
{
int fx = find(x),fy = find(y);
if (fx != fy) f[fy] = fx;
}
int main()
{
int n,k,num = 0;
scanf("%d%d",&n,&k);
for (int i = 1;i<=3 * n;i++) f[i] = i;//初始化
for (int i = 1;i<=k;i++)
{
int d,x,y;
scanf("%d%d%d",&d,&x,&y);
if ((d == 2 && x == y) || (x > n) || (y > n))//判断符不符合输入条件
{
num++;
continue;
}
if (d == 1)
{
if ((find(x) == find(y + n)) || (find(x) == find(y+2*n))) // 如果x是y的猎物或者x是y的天敌,则这条信息错误
{
num++;
}
else
{
insert(x,y);//把 x 和 y 并起来
insert(x+n,y+n);//把 x 的猎物和 y 的猎物并起来
insert(x+2*n,y+2*n);//把 x 的天敌和 y 的天敌并起来
}
}
else
{
if ((find(x) == find(y + n)) || (find(x) == find(y)) )
//如果 x 是 y 的猎物 或者 x 和 y 是同类,则输入错误。
{
num++;
}
else
{
insert(x,y + 2 * n);//把 x 和 y 的天敌并起来
insert(x + n,y);//把 x 的猎物 和 y 并起来
insert(x + 2 * n,y+n);//把 x 的天敌和 y 的猎物并起来
}
}
}
printf("%d",num);
return 0;
}
总而言之,并查集就是把相同类的并起来。
起码现在的我是这么理解的。
本文来自博客园,作者:Un-Defined,转载请保留本文署名Un-Defined,并在文章顶部注明原文链接:https://www.cnblogs.com/EIPsilly/p/15606162.html