備戰藍橋杯決賽----堅持第六天!!!
阿新 • • 發佈:2019-02-04
今天的學習時間是從晚6點開始,一道簡單的題目,消耗了我三個半小時,其實是先看了一道關於hash的題目,沒有看懂,就用看了一道題目,正好碰到了簡單的並查集。雖然今天也是很苦逼,但是心情似乎沒有那麼差了,也許是我來學習之前就想明白了,不想說自己生活上的事情,我們單單對於演算法來講,千萬不要因為你沒有AC一道題目,沒有看懂一道題目的解析而感到沮喪,傷心。。更不能把這種情緒帶到生活的其他方面。反而我們可以通過其他事情,來緩和我們對於沒有AC的沮喪心情。
題目:
問題描述 w星球的一個種植園,被分成 m * n 個小格子(東西方向m行,南北方向n列)。每個格子裡種了一株合根植物。這種植物有個特點,它的根可能會沿著南北或東西方向伸展,從而與另一個格子的植物合成為一體。
如果我們告訴你哪些小格子間出現了連根現象,你能說出這個園中一共有多少株合根植物嗎?輸入格式 第一行,兩個整數m,n,用空格分開,表示格子的行數、列數(1<m,n<1000)。
接下來一行,一個整數k,表示下面還有k行資料(0<k<100000)
接下來k行,第行兩個整數a,b,表示編號為a的小格子和編號為b的小格子合根了。
格子的編號一行一行,從上到下,從左到右編號。
比如:5 * 4 的小格子,編號:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
17 18 19 20樣例輸入5 4
16
2 3
1 5
5 9
4 8
7 8
9 10
10 11
11 12
10 14
12 16
14 18
17 18
15 19
19 20
9 13
13 17樣例輸出5樣例說明 其合根情況參考下圖
剛開始我也是沒有思路,然後百度,看到其他博主對此題分析的第一句話,都是簡單,並查集操作。然後我就立刻停止了瀏覽,自己寫了起來,因為自己之前看過並查集,感覺再回憶一下,應該能AC這題。所以我又理了一遍並查集,如果有不懂並查集的,可以先跳過下面的答案,看看我下面並查集的構建過程。
程式碼:
#include<iostream> using namespace std; const int MAX=1000001;//陣列範圍一定要明確 int parent[MAX]; int rank[MAX]; int find(int p){ while(parent[p]!=p){ parent[p] = parent[parent[p]]; p=parent[p]; } return p; } void uniono(int p,int q){ int pID = find(p); int qID = find(q); if(pID==qID){ return; } if(rank[pID]>rank[qID]){ parent[qID]=pID; }else if(rank[pID]<rank[qID]){ parent[pID]=qID; }else{ parent[qID]=pID; rank[pID]+=1; } } int main(){ int m,n; cin>>m>>n; int k=m*n; for(int i=1;i<=k;i++){ parent[i]=i; rank[i]=1; } int x,y,l; cin>>l; for(int i=0;i<l;i++){ cin>>x>>y; uniono(x,y); } int *p = new int[k+1]; for(int i=1;i<=k;i++){ p[find(i)]=1;//這裡之前寫成parent[i]就一直不能通過,改為find(i)後可以通過,至於原因,想到再說吧 } int s=0; for(int i=1;i<=k;i++){ if(p[i]==1){ s+=1; } } cout<<s; return 0; }
並查集的構建,關鍵在於需要設定兩個方法:uniono(合併)與find(查詢)
原始的簡單方法:
int id[10];//構建一個id陣列,用於表示節點間的關係。如:陣列奇數元素定義為0,偶數元素定義為1,則表示奇數元素節點互相相連,偶數元素節點互相相連
int find(int p){
return id[p];
}
void uniono(int p,int q){
int pID = find(p);
int qID = find(q);
if(pID==qID){
return;
}else{
id[pID]=id[qID];
}
}
採用父節點的思想,所有連線節點屬於一個父節點
int parent[10];
int find(int p){
while(parent[p]!=p){
p=parent[p];
}
return p;
}
void uniono(int p,int q){
int pID = find(p);
int qID = find(q);
if(pID==qID){
return;
}
parent[pID]=qID;
}
基於rank的優化
int parent[10];
int rank[10];
int find(int p){
while(parent[p]!=p){
p=parent[p];
}
return p;
}
void uniono(int p,int q){
int pID = find(p);
int qID = find(q);
if(pID==qID){
return;
}
if(rank[pID]>rank[qID]){
parent[qID]=pID;
}else if(rank[pID]<rank[qID]){
parent[pID]=qID;
}else{
parent[qID]=pID;
rank[pID]+=1;
}
}
路徑壓縮:
int parent[10];
int rank[10];
int find(int p){
while(parent[p]!=p){
p = parent[parent[p]];
p=parent[p];
}
return p;
}
void uniono(int p,int q){
int pID = find(p);
int qID = find(q);
if(pID==qID){
return;
}
if(rank[pID]>rank[qID]){
parent[qID]=pID;
}else if(rank[pID]<rank[qID]){
parent[pID]=qID;
}else{
parent[qID]=pID;
rank[pID]+=1;
}
}