带权并查集经典习题:POJ-2492 A Bug's Life; POJ-1182 食物链;hihoCoder1515 分数调查

带权并查集讲解:https://blog.csdn.net/Floraqiu/article/details/79226320


POJ - 2492 A Bug's Life

POJ - 1182 食物链

hihoCoder1515 分数调查

拙见:带权并查集 就是为每个节点增加一个value,表示这个点与根节点的某种关系,然后可以通过两个节点和根节点的关系来判断这两个节点的关系,核心就是维护这个value。

                                                 A Bug's Life

Time Limit: 10000MS   Memory Limit: 65536K

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!

题意:

n组输入,每组输入第一行给出n,m表示有n只昆虫依此编号1~n,后面m行输入。 后面m行,每行两个数x y,表示x和y有一腿,昆虫分雌雄,问有无同性恋

思路:

带权并查集,为每个节点(代表一只昆虫)增加一个value值表示此节点(昆虫)与根节点(还是个昆虫)的性别关系,0表示为同性,1表示异性。如果输入x y时(它俩有一腿)发现它俩在同一个集合内且所处节点value值相同,说明这俩时同性恋。

ACCode:

#include <iostream>

using namespace std;

const int maxn = 1e6+5;
int f[maxn],sex[maxn];
void init(int n) 
{
	for(int i=1;i<=n;i++) {
		f[i] = i;
		sex[i] = 0;
	}
}
int getf(int x)
{
	if(f[x] == x)	return x;
	int t = f[x];
	f[x] = getf(f[x]);
	sex[x] = (sex[x]+sex[t])%2; 
	return f[x];
}
void Merge(int x,int y)
{
	int fx = getf(x);
	int fy = getf(y);
	if(fx != fy) {
		f[fy] = fx;
		sex[fy] = (sex[x]+sex[y]+1)%2;
	}
}

bool check(int x,int y)	// 判断是否可以确定为同性 
{
	int fx = getf(x);
	int fy = getf(y);
	if(fx == fy) {
		if(sex[x] == sex[y])
			return true;
	}
	return false;
}
int main()
{
	int T,n,m,Case=1;
	scanf("%d",&T);
	while(T--) {
		scanf("%d%d",&n,&m);
		init(n);
		bool flag = false;
		int x,y;
		for(int i=1;i<=m;i++) {
			scanf("%d%d",&x,&y);
			if(check(x,y)) {
				flag = true;
			}
			else
				Merge(x,y);
		}
		if(flag)
			printf("Scenario #%d:\nSuspicious bugs found!\n",Case++);
		else 
			printf("Scenario #%d:\nNo suspicious bugs found!\n",Case++);	
		if(T!=0)
			printf("\n"); 
	}
	return 0;
}

                                                     食物链

Time Limit: 1000MS   Memory Limit: 10000K

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

解题思路:

为每个节点(表示一种动物)增加一个value,表示其与其根节点的关系。0表示与根节点同类,1表示被根节点吃,2表示吃根节点(好像是这个顺序,或者换一下~)。每次输入一句话1/2 x y 的时候,判断x y是否在同一个集合,如果不是,就把它俩加到同一集合并更新value;如果在同一集合,则可以根据他俩和共同根节点的关系判断他俩的关系,如果得出的关系和输入给出的相同,则为真话,不同,则为假话。

ACCode:

#include <iostream>

using namespace std;
const int maxn = 5e4+5;
int f[maxn],rel[maxn],ans,n;
void init()
{
	for(int i=1;i<=n;i++) {
		f[i] = i;
		rel[i] = 0;
	}	
	ans = 0;
}
int getf(int x)
{
	if(f[x] == x)	return x;
	// 路径压缩
	int t = f[x];
	f[x] =  getf(f[x]);
	rel[x] = (rel[x]+rel[t])%3;
	return f[x];
}
void Merge(int r,int x,int y)
{
	int fx = getf(x);
	int fy = getf(y);
	if(fx != fy) {
		f[fx] = fy;
		rel[fx] = (rel[y]-rel[x]+r+3)%3; 
	}
}
bool check(int r,int x,int y)
{
	if(x > n || y > n)
		return false;
	if(r == 1 && x == y)
		return false;
	if(getf(x) == getf(y)) 
		return r ==  ((rel[x]-rel[y])%3+3)%3;
	return true;
}
// 只要出现了关于x和y的实话,就把x和y加到一个集合中,存储他们各自和根节点的关系
// 下次判断的时候通过他俩和根节点的关系从而推出他俩的关系 ps:else二维数组你开的开? 
int main()
{

	int k;
	scanf("%d%d",&n,&k);
	init();
	for(int i=1;i<=k;i++) {
		int t1,t2,t3;
		scanf("%d%d%d",&t1,&t2,&t3);
		t1--;	//关系表示变为自定义的关系表示 
		if(check(t1,t2,t3))
			Merge(t1,t2,t3);
		else 
			ans++;
	}
	printf("%d\n",ans);
	return 0;
}

#1515 : 分数调查

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

小Hi的学校总共有N名学生,编号1-N。学校刚刚进行了一场全校的古诗文水平测验。  

学校没有公布测验的成绩,所以小Hi只能得到一些小道消息,例如X号同学的分数比Y号同学的分数高S分。  

小Hi想知道利用这些消息,能不能判断出某两位同学之间的分数高低?

输入

第一行包含三个整数N, M和Q。N表示学生总数,M表示小Hi知道消息的总数,Q表示小Hi想询问的数量。  

以下M行每行三个整数,X, Y和S。表示X号同学的分数比Y号同学的分数高S分。  

以下Q行每行两个整数,X和Y。表示小Hi想知道X号同学的分数比Y号同学的分数高几分。  

对于50%的数据,1 <= N, M, Q <= 1000  

对于100%的数据,1 <= N, M, Q<= 100000 1 <= X, Y <= N -1000 <= S <= 1000

数据保证没有矛盾。

输出

对于每个询问,如果不能判断出X比Y高几分输出-1。否则输出X比Y高的分数。

样例输入

10 5 3  
1 2 10  
2 3 10  
4 5 -10  
5 6 -10  
2 5 10  
1 10  
1 5  
3 5

样例输出

-1  
20  
0

思路:

value表示与根节点的分数差,

ACCode:

#include <iostream>

using namespace std;
const int maxn = 1e5+5;

int f[maxn],dis[maxn];	//与根节点的分数差
void init(int n)
{
	for(int i=1;i<=n;i++) {
		f[i] = i;
		dis[i] = 0;
	}
}
int getf(int x)
{
	if(f[x] == x)	return x;
	int t = f[x];
	f[x] = getf(f[x]);
	dis[x] = dis[x]+dis[t];
	return f[x];
}
void Merge(int x,int y,int d)
{
	int fx = getf(x);
	int fy = getf(y);
	if(fx != fy) {
		f[fy] = fx;
		dis[fy] = d+dis[x]-dis[y];
	}
}
int main()
{
	int n,m,q;
	scanf("%d%d%d",&n,&m,&q);
	init(n);	
	int x,y,d;
	for(int i=1;i<=m;i++) {
		scanf("%d%d%d",&x,&y,&d);
		Merge(x,y,d);
	}
	for(int i=1;i<=q;i++){
		scanf("%d%d",&x,&y);
		if(getf(x) == getf(y))
			printf("%d\n",dis[y]-dis[x]);
		else
			printf("-1\n");
	}
	return 0; 
} 

猜你喜欢

转载自blog.csdn.net/weixin_42765557/article/details/90140599