a445 - 新手訓練系列- 我的朋友很少
題目描述
題目描述了一個朋友關係的網路,給定 N 個人,M 個朋友關係,以及 Q 個詢問。對於每個詢問,需要判斷 P 和 Q 是否為朋友。朋友關係具有傳遞性,即如果 A 是 B 的朋友,B 是 C 的朋友,那麼 A 和 C 也是朋友。
解題思路
本題可以使用 Disjoint Set (也稱為 Union-Find) 資料結構來解決。Disjoint Set 用於處理不相交集合的合併和查找操作。
- 初始化: 建立一個大小為 N+1 的陣列
a,其中a[i]初始化為i。這表示每個元素最初都屬於自己的集合。 - Union 操作: 對於每條朋友關係 (x, y),找到 x 和 y 所屬的集合的根節點。如果根節點不同,則將一個集合的根節點指向另一個集合的根節點,表示合併這兩個集合。
- Find 操作: 找到元素所屬集合的根節點。使用路徑壓縮優化,將路徑上的每個節點直接指向根節點,以提高後續查找的效率。
- 查詢: 對於每個詢問 (x, y),找到 x 和 y 所屬的集合的根節點。如果根節點相同,則 x 和 y 是朋友,輸出 ":)"; 否則,輸出 ":("。
複雜度分析
- 時間複雜度: O(M * α(N) + Q * α(N)),其中 α(N) 是反阿克曼函數,增長非常緩慢,可以視為常數。因此,時間複雜度近似於 O(M + Q)。
- 空間複雜度: O(N),用於儲存 Disjoint Set 陣列
a。
程式碼
#include <iostream>
using namespace std;
int a[1000001]={0};
int ff(int n){
if(a[n]==n)
return n;
return a[n]=ff(a[n]);
}
int main(){
int N,M,Q;
cin >> N >> M >> Q;
for(int i=1;i<=N;i++)
a[i]=i;
while(M--){
int x,y;
cin >> x >> y;
x = ff(x);
y = ff(y);
if(x!=y)
a[y] = x;
}
while(Q--){
int x,y;
cin >> x >> y;
if(ff(x)==ff(y))
printf(":)\n");
else
printf(":(\n");
}
}