poj 1703 并查集

题目链接:点击打开链接

题目大意:

一共有N个人,给出M个操作分为两种:

1、A   a  b  :提问a和b是否是同一个帮派的。有三种答案:是,不是和不确定

2、D  a  b   :a和b不是同一个帮派的。

解题思路:

种类并查集,在一个集合里的证明他们之间有关系,种类里有0,和1两种。0代表着同父节点相同势力,1代表不同。

主要是不在同一集合时合并和查找操作;

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
const int N = 100005;
int vis[N];//与父节点属于同一帮派为0,不一帮派为1
int father[N];
int find(int x) {//每次find后vis的值将变正确
	if (father[x] != x) {
		int t = find(father[x]);
		////此处很重要,是通过这个节点与原来父节点的关系(是否是同一集合的问题)求这个节点现在与根节点的关系(异或关系)
		vis[x] = (vis[father[x]] + vis[x]) % 2;
		father[x] = t;
	}//顺序不可变
	return father[x];
}
void merge(int x,int y) {
	int a = find(x);
	int b = find(y);
	father[a] = b;//将x所在的树连接到y所在的树的下边
	if (vis[y] == 0)vis[a] = 1 - vis[x];//如果y与b在同一帮派,又因为y与x在不同帮派,推出a和b在不在同一帮派
	else vis[a] = vis[x];//与上相同
}
int main() {
	int T;
	cin >> T;
	while (T--) {
		int n, t;
		char temp[20];
		cin >> n >> t;
		for (int i = 0; i <= n; i++)father[i] = i;
		memset(vis, 0, sizeof(vis));
		string s;
		while (t--) {
			int a, b;
			scanf("%s %d %d", temp, &a, &b);//输入数据
			s = temp;//char->string
			if (s == "A") {
				if (find(a) != find(b)) {//这里面包含find函数,所以vis值正确,为后面判断做铺垫
					printf("Not sure yet.\n");
					continue;
				}
				else {
					if (vis[a]==vis[b])printf("In the same gang.\n");//上面的find会使vis正确
					else printf("In different gangs.\n");
				}
			}
			else merge(a, b);//两个合到同一集合
		}
	}
}

猜你喜欢

转载自blog.csdn.net/y201619819/article/details/81042420