寒假私训——并查集 PID577 / 团伙

并查集例题—团伙

题目描述

1920年的芝加哥,出现了一群强盗。如果两个强盗遇上了,那么他们要么是朋友,要么是敌人。而且有一点是肯定的,就是:

**我朋友的朋友是我的朋友。
我敌人的敌人也是我的朋友。 ** (关键!!!!)

两个强盗是同一团伙的条件是当且仅当他们是朋友。现在给你一些关于强盗们的信息,问你最多有多少个强盗团伙。

输入格式

输入的第一行是一个整数N(2<=N<=1000),表示强盗的个数(从1编号到N)。 第二行M(1<=M<=5000),表示关于强盗的信息条数。 以下M行,每行可能是F p q或是E p q(1<=p q<=N),F表示p和q是朋友,E表示p和q是敌人。输入数据保证不会产生信息的矛盾。
输出格式

输出只有一行,表示最大可能的团伙数。
样例输入
6
4
E 1 4
F 3 5
F 4 6
E 1 2
样例输出
3

解题思路

就像题目中说的一样,我的朋友的朋友就是我的朋友,我敌人的敌人也是我的朋友 ,所以,此题分成两个数组,朋友数组和敌人数组。在朋友数组中搜索,有几个根节点,就是有几个团伙。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#define maxn 5005
#define M 1e9+5
using namespace std;
typedef long long ll;
using namespace std;
int pref[maxn],pree[maxn];

int findx(int x){      //查找x的根节点
	while(pref[x]!=x)
                    x=pref[x];
	return x;
}

void join(int x,int y) {//将x,y建立羁绊
	x=findx(x);
	y=findx(y);
               pref[x]=y;
}

int main(){
	int n,m,x,y;
	char p;
	cin>>n>>m;
	for(int i=0;i<n;i++){
		pref[i]=i; //pre数组是记录父节点的,现在在初始化
	}
	for(int i=0;i<m;i++){
		cin>>p>>x>>y;
		if(p=='F')
                                             join(x,y);
                              else{
                                             if(pree[x]==0) pree[x]=findx(y);//x没有敌人
                                             else join(pree[x],findx(y)); //x有敌人,将x的敌人头领和y的头领结合
                                             if(pree[y]==0) pree[y]=findx(x);
                                             else join(pree[y],findx(x));  //这里,敌人的敌人就是朋友
                              }
	}
	int num=0;
	for(int i=0;i<n;i++){
                              if(pref[i]==i)  //这里要注意,不能搜索pree数组,因为
                                             num++;
	}
	cout<<num<<endl;
	return 0;
}
发布了36 篇原创文章 · 获赞 1 · 访问量 1399

猜你喜欢

转载自blog.csdn.net/atnanajiang/article/details/104030792