1. 程式人生 > >7-21 部落(25 分)

7-21 部落(25 分)

7-21 部落(25 分)

在一個社群裡,每個人都有自己的小圈子,還可能同時屬於很多不同的朋友圈。我們認為朋友的朋友都算在一個部落裡,於是要請你統計一下,在一個給定社群中,到底有多少個互不相交的部落?並且檢查任意兩個人是否屬於同一個部落。

輸入格式:

輸入在第一行給出一個正整數N104),是已知小圈子的個數。隨後N行,每行按下列格式給出一個小圈子裡的人:

K P[1] P[2]  P[K]

其中K是小圈子裡的人數,P[i]i=1,,K)是小圈子裡每個人的編號。這裡所有人的編號從1開始連續編號,最大編號不會超過104

之後一行給出一個非負整數Q104),是查詢次數。隨後Q行,每行給出一對被查詢的人的編號。

輸出格式:

首先在一行中輸出這個社群的總人數、以及互不相交的部落的個數。隨後對每一次查詢,如果他們屬於同一個部落,則在一行中輸出Y,否則輸出N

輸入樣例:

4
3 10 1 2
2 3 4
4 1 5 7 8
3 9 6 4
2
10 5
3 7

輸出樣例:

10 2
Y
N
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int c[1000001];
int vis[1000002]; //定義標記陣列
int find(int x){
	if(c[x]==x)
	 return x;
	else
	 return c[x]=find(c[x]);
}
void f(int x,int y){
	int a=find(x);
	int b=find(y);
	if(a!=b)
	 c[a]=b;
}
int main(){
	int n,m,k,l,q,w,e,r,p;
	int i,j=0,cnt=0;
	cin>>n;
	for(i=1;i<10001;i++){
		c[i]=i;
	}
	memset(vis,0,sizeof(vis));
	for(i=0;i<n;i++){
		cin>>p;
		cin>>q;
		vis[q]=1;// 標記出現的成員,出現就把該成員記為1 
		p--;
		while(p--){
			cin>>w;
			vis[w]=1;
			f(q,w);
		}
	}
	for(i=0;i<10001;i++) //  在最大範圍內,遍歷該陣列
	{		
	    if(vis[i]==1){//如果該數字為1的話,證明該數字已經被標記了,那麼就可以記錄個數
		cnt++;  //這樣就算出了成員的總人數
		}
	}
	cout<<cnt<<" ";
	for(i=1;i<=cnt;i++){ //在成員的總人數範圍內 找部落的個數
		if(c[i]==i)  // 如果是同一個部落裡的人的話,數組裡的數字是和下標不一樣的 如果數組裡面的數字和下標一樣的話 那麼就是一個部落
		 j++;
	}
	cout<<j<<endl;
	cin>>w;
	while(w--){
		cin>>r>>p;
		if(find(r)==find(p))  //判斷某兩個成員是否是同一個部落裡的成員,如果經過查詢,它們都能歸結於同一個數字的話,那麼就是同一個部落的成員,否則就不是。
		 cout<<"Y"<<endl;
		else
		 cout<<"N"<<endl;
	}
	return 0;
}