7-25 朋友圈 (25 分)(详解+并查集的了解和应用)
一:題目
某學校有N個學生,形成M個俱樂部。每個俱樂部里的學生有著一定相似的興趣愛好,形成一個朋友圈。一個學生可以同時屬于若干個不同的俱樂部。根據“我的朋友的朋友也是我的朋友”這個推論可以得出,如果A和B是朋友,且B和C是朋友,則A和C也是朋友。請編寫程序計算最大朋友圈中有多少人。
輸入格式:
輸入的第一行包含兩個正整數N(≤30000)和M(≤1000),分別代表學校的學生總數和俱樂部的個數。后面的M行每行按以下格式給出1個俱樂部的信息,其中學生從1~N編號:
第i個俱樂部的人數Mi(空格)學生1(空格)學生2 … 學生Mi
輸出格式:
輸出給出一個整數,表示在最大朋友圈中有多少人。
輸入樣例:
7 4
3 1 2 3
2 1 4
3 5 6 7
1 6
輸出樣例:
4
二:思路
利用并查集,求得根節點的得數組,再用map<int,int> 來計算當中重復次數多的個數 也就是根節點相同的個數最大值
三:上碼
#include<bits/stdc++.h> using namespace std;int father[30000]; //int find( int x){ // // while( x != father[x] ) // { // x = father[x]; // } // // return x; //}//壓縮路徑 int find(int x){int r=x;while(father[r]!=r)r=father[r]; //找到他的前導結點int i=x,j;while(i!=r){ //路徑壓縮算法j=father[i]; //記錄x的前導結點father[i]=r; //將i的前導結點設置為r根節點i=j;}return r; } void merge(int x,int y) {int a = find(x);//x的根節點為a int b = find(y);//y的根節點為bif( a != b )father[b] = a;//那么將b的根節點 設為 a }int main() {int N,M;cin >> N >> M;for( int i = 1; i <= N; i++ )father[i] = i; //設置根節點為數組下標,另外元素值為索引 for( int j = 0; j < M; j++ ){int num;cin >> num;vector<int>v;for( int k = 0; k < num; k++ ){int numPeople;cin >> numPeople;v.push_back(numPeople); }for( int i = 0; i < num-1; i++ ){if( find(v[i]) != find(v[i+1]) )merge(v[i],v[i+1]);//比如剛開始的 1和2 他們原來的根節點不同,所以合并 也就是將索引值為2的數組值改為1 即根節點值為1 } }map<int,int>m;for( int i = 1; i <= N; i++){m[find(i)]++; //這里是find(i) 不能是father[i] 否則最后一個測試點答案錯誤} map<int,int>:: iterator t;int max = 0;for(t = m.begin(); t!= m.end(); t++){if( max < t->second )max = t->second;}cout << max;}//7 4 //3 1 2 3 //2 1 4 //3 5 6 7 //1 6// 7 4 // 2 1 4 // 3 5 6 7 // 1 6 // 3 1 2 3四:并查集的相關知識
這道題用到了并查集,所以我就學了一下并查集,所以把自己的見解也分享給大家(建議 先看視頻 再瀏覽 博客 再自己敲一遍 學習效率高而已,我總是亂著來 以為看幾篇博客就會了,其實最后還是老老實實 去B站看大佬講解視頻 才搞懂)
1:并查集
查集是一種樹型的數據結構,
用于處理一些不相交集合(Disjoint Sets)的合并及查詢問題
1:查詢元素a和元素b是否屬于同一組
2:合并元素a和元素b所在組 (將有相同元素的元素 合并為一個組 )
3:需要初始化一個數組存放父節點,其索引值 代表元素
2:并查集的AC代碼(模板`)
/*并查集是一種樹型的數據結構,用于處理一些不相交集合(Disjoint Sets)的合并及查詢問題1:查詢元素a和元素b是否屬于同一組2:合并元素a和元素b所在組 (將有相同元素的元素 合并為一個組 ) 3:需要初始化一個數組存放父節點,其索引值 代表元素 */#include<bits/stdc++.h> using namespace std;int father[100]; int find( int x){while( x != father[x] ){x = father[x];}return x; } void merge(int x,int y) {int a = find(x);//x的根節點為a int b = find(y);//y的根節點為bif( a != b )father[b] = a;//那么將b的根節點 設為 a }int main() {//初始化: 我們將每一個結點的前導結點設置為自己,//如果在merge函數時未能形成連通,將獨立成點for( int i = 0; i < 10; i++ ){father[i] = i;}}上方的find函數 效率不高,當處理大數據時,使用并查集查找時,如果查找次數很多,那么使用樸素版的查找方式肯定要超時。比如,有一百萬個元素,每次都從第一百萬個開始找,這樣一次運算就是106,如果程序要求查找個一千萬次,這樣下來就是1013,肯定要出問題的。
所以有了壓縮路徑的算法(就是一棵樹只有葉節點)
void merge(int x,int y){int a=find(x);//x的根節點為aint b=find(y);//y的根節點為bif(a!=b)//如果a,b不是相同的根節點,則說明ab不是連通的pre[a]=b;//我們將ab相連 將a的前導結點設置為b }如有疑問 請留言! 加油陌生的你
總結
以上是生活随笔為你收集整理的7-25 朋友圈 (25 分)(详解+并查集的了解和应用)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是生物钟紊乱
- 下一篇: 7-27 家谱处理 (30 分)(详解+