1. 程式人生 > >資料結構與演算法題目集7-25——朋友圈

資料結構與演算法題目集7-25——朋友圈

我的資料結構與演算法題目集程式碼倉:https://github.com/617076674/Data-structure-and-algorithm-topic-set

原題連結:https://pintia.cn/problem-sets/15/problems/840

題目描述:

知識點:深度優先遍歷、並查集

思路一:深度優先遍歷

用set<int> club[]儲存每個俱樂部對應的學生資訊,用set<int> student[]儲存每個學生對應的俱樂部資訊。

對M個俱樂部進行深度優先遍歷,用bool visited[]陣列標記某俱樂部是否已被訪問過。

遍歷M個俱樂部,如果當前俱樂部未被訪問過,則清空set<int> cluster,代表即將加入一個新的學生編號叢集,深度優先遍歷當前俱樂部編號。

深度優先遍歷函式如下:

在visited陣列中標記當前節點nowVisit已被訪問過,將當前俱樂部的學生加入到cluster中,並遍歷當前俱樂部的所有學生,所有學生又遍歷其對應的所有俱樂部,一旦發現未訪問的俱樂部,即遞迴呼叫函式,深度優先遍歷該俱樂部。

時間複雜度是O(M * N)。空間複雜度是O(30001)。

C++程式碼:

#include<iostream>
#include<set>

using namespace std;

int N, M;
set<int> club[1000], student[30001], cluster;
bool visited[1000];
int result = 0;

void dfs(int nowVisit);

int main(){
	scanf("%d %d", &N, &M); 
	for(int i = 0; i < M; i++){
		int Mi, num;
		scanf("%d", &Mi);
		for(int j = 0; j < Mi; j++){
			scanf("%d", &num);
			student[num].insert(i);
			club[i].insert(num);
		}
	}
	fill(visited, visited + M, false);
	for(int i = 0; i < M; i++){
		if(!visited[i]){
			cluster.clear();
			dfs(i);
			if(cluster.size() > result){
				result = cluster.size();
			}
		}
	}
	printf("%d\n", result);
	return 0; 
}

void dfs(int nowVisit){
	visited[nowVisit] = true;
	for(set<int>::iterator it = club[nowVisit].begin(); it != club[nowVisit].end(); it++){
		cluster.insert(*it);
	}
	for(set<int>::iterator it1 = club[nowVisit].begin(); it1 != club[nowVisit].end(); it1++){
		for(set<int>::iterator it2 = student[*it1].begin(); it2 != student[*it1].end(); it2++){
			if(!visited[*it2]){
				dfs(*it2);
			}
		}
	}
}

C++解題報告:

思路二:並查集

每個俱樂部的學生擁有相同的父親節點。

時間複雜度和空間複雜度均是O(N)。

C++程式碼:

#include<iostream>
#include<set>

using namespace std;

int N, M, father[30001];

int findFather(int x);
void unionTwo(int a, int b);

int main(){
	scanf("%d %d", &N, &M);
	for(int i = 1; i <= N; i++){	//並查集的初始化 
		father[i] = i;
	}
	for(int i = 0; i < M; i++){
		int Mi;
		scanf("%d", &Mi);
		int students[Mi];
		for(int j = 0; j < Mi; j++){
			scanf("%d", &students[j]);
		}
		for(int j = 1; j < Mi; j++){
			unionTwo(students[j - 1], students[j]);
		}
	}
	int count[N + 1];
	fill(count + 1, count + N + 1, 0);
	for(int i = 1; i <= N; i++){
		count[findFather(i)]++;
	}
	int result = 0;
	for(int i = 1; i <= N; i++){
		if(count[i] > result){
			result = count[i];
		}
	}
	printf("%d\n", result);
	return 0; 
}

int findFather(int x){
	int a = x;
	while(x != father[x]){
		x = father[x];
	}
	while(a != father[a]){
		int z = a;
		a = father[a];
		father[z] = x;
	}
	return x;
}

void unionTwo(int a, int b){
	int a_father = findFather(a);
	int b_father = findFather(b);
	if(a_father != b_father){
		father[a_father] = b_father;
	}
}

C++解題報告: