下面的**是 tyvj p1251 的**
題目不在贅述 是乙個裸的的並查集題目
並查集詳細講解見 神牛的部落格)
#include
#include
#include
#include
using namespace std;
struct st[5010];
int ans[5010],n,m,k;
void build(int x)}
int get(int x)
return i;
}void link(int x,int y)
}int main()
for(int i=1;i<=k;i++)
for(int i=1;i<=k;i++)
return 0;
關於並查集應用的筆記
關於動態的連通性見神牛的部落格
最裸的並查集就只有表示乙個集合的功能,支援動態的合併,查詢兩者是否屬於乙個集合,這部分內容太簡單,請自行baidu。
在並查集上可以加入邊權,成為加權並查集,一般來說這類題目形式比較單一,純屬個人娛樂吧。。
加權並查集裸題——銀河英雄傳說
這是一道最裸的加權並查集,對於每乙個節點維護乙個到最老最先的邊權值和,再在祖先上維護乙個size,表示集合的大小。wikioi上的題解有個水表說不能路徑壓縮。。。怎麼可能嘛!!!我們仔細思考一下,每乙個點在乙個集合中只會被壓縮一次,壓縮之後就會被連線到祖先上,到祖先的權值和等於到原來的父親的權值加上原來的父親到祖先的權值和,只需要在壓縮的時候更新一下就好了。合併的時候,把兩個集合(不妨設a,b)合併在一起,假如把a併入b,則把a的祖先節點連在b的祖先上,邊權設為b的size。相當於把a集合直接接在b的後面,如此,這個問題就被很好的解決了。
上面這道是裸題,下面有乙個看起來不裸的的水題:
加權並查集弱題——食物鏈
初一看這道題似乎和並查集關係不大,但是仔細觀察可以發現,不同的個體存在一些關係。我們將物種設為0,1,2三種,則給出的條件分為兩種——1.兩個個體數字(物種)相同。2,個體a數字=(個體b數字+1)%3 。是否有了一點發現呢,如果是相同的數字,並且不屬於同乙個集合,就想合併辦法讓他們之間的權值變為0(mod 3),同理,可以讓其數字變為1或2(mod 3),只需要在路徑壓縮的時候取模就行了。水題解決,**用下一道的吧。。。
原創題——魏總數星星
魏總數星星
(star.cpp/c/pas
)【描述】
魏總,也就是dp
魏,非常喜歡星星,有一天他躺在草坪上數星星。天上共有
i顆星星,魏總把天空分成了
k個扇形,繞著天空的中心——月亮排布。月亮看見魏總喜歡星星,非常不爽,她就想考一下魏總。月亮給出
n隊星星的相互關係,形如
a b p表示b
星星在a
星星所在扇形區域的順時針方向第
p個扇形內(
0<=p<=k
)(p==0
時表示在同乙個扇形內)。最後月亮要詢問
m次,形如
a b表示詢問
a b兩星是否在乙個扇形內,是則輸出「
yes」,不是則輸出「
no」,不知道則輸出「
unknown
」。由於月亮看魏總喜歡星星變得心情急躁,可能有一些關係與前面的關係矛盾,則這些關係無效。月亮說如果不能把她的所有詢問答對就要發出強光,讓魏總看不到星星,而本來是大神的魏總因為想見到星星不能程式設計,只有把這個艱鉅的任務交給你了。
【輸入】
第一行四個整數i,k
,n,m
表示i個星星,
k個扇形,
n個關係,
m個詢問。
接下來n
行,每行三個整數
a b p
表示表示
b星星在
a星星所在扇形區域的順時針方向第
p個扇形內。
接下來m
行,每行兩個整數
a b表示詢問a,
b是否在同乙個扇形內。
【輸出】 共m
行,每行為「
yes」或「
no」或「
unknown
」對應每乙個詢問
【樣例輸入】
5 5 3 3
1 2 1
2 4 2
4 5 2
1 23 4
1 5【樣例輸出】 no
unknown
yes【資料範圍】
20%,魏總數不超過
100個星星,月亮詢問不超過
100次,天空被分成不超過
10個區域。
50%,魏總數不超過
4000
個星星,月亮詢問不超過
4000
次,天空被分成不超過
1000
個區域。
100%,魏總數不超過
100000
個星星,月亮詢問不超過
100000
次,天空被分成不超過
10000
個區域,關係數少於
200000。
其實很容易發現這道題和食物鏈是一模一樣的,只不過把邊權值改為了比較大的數,只需稍微改一下**即可,**如下:
總結:並查集可以處理沒有分離操作的一類問題,可以在極快的時間內處理元素間相互關係的問題,好寫好用,就是沒什麼地方用。。。
下面的內容是的筆記
首先還是回顧和總結一下關於並查集的幾個關鍵點:
以樹作為節點的組織結構,結構的形態很是否採取優化策略有很大關係,未進行優化的樹結構可能會是「畸形」樹(嚴重不平衡,頭重腳輕,退化成煉表等),按尺寸(正規說法叫做秩,後文全部用秩來表示)進行平衡,同時輔以路徑壓縮後,樹結構會高度扁平化。
雖然組織結構比較複雜,資料表示方式卻十分簡潔,主要採用陣列作為其底層資料結構。一般會使用兩個陣列(parent-link array and size array),分別用來儲存當前節點的父親節點以及當前節點所代表子樹的秩。第乙個陣列(parent-link array)無論是否優化,都需要使用,而第二個陣列(size array),在不需要按秩合併優化或者不需要儲存子樹的秩時,可以不使用。根據應用的不同,可能需要第三個陣列來儲存其它相關資訊,比如hdu-3635中提到的「轉移次數」。
主要操作包括兩部分,union以及find。union負責對兩顆樹進行合併,合併的過程中可以根據具體應用的性質選擇是否按秩優化。需要注意的是,執行合併操作之前,需要檢查待合併的兩個節點是否已經存在於同一顆樹中,如果兩個節點已經在一棵樹中了,就沒有合併的必要了。這是通過比較兩個節點所在樹的根節點來實現的,而尋找根節點的功能,自然是由find來完成了。find通過parent-link陣列中的資訊來找到指定節點的根節點,同樣地,也可以根據應用的具體特徵,選擇是否採用路徑壓縮這一優化手段。然而在需要儲存每個節點代表子樹的秩的時候,則無法採用路徑壓縮,因為這樣會破壞掉非根節點的尺寸資訊(注意這裡的「每個」,一般而言,在按秩合併的時候,需要的資訊僅僅是根節點的秩,這時,路徑壓縮並無影響,路徑壓縮影響的只是非根節點的秩資訊)。
不存在環路(對於有向圖,不存在環路也就意味著不存在強連通子圖)
滿足邊數加一等於頂點數的規律(不考慮重邊和指向自身的邊)
第一條,在並查集中應該如何實現呢?
現在我們對並查集也有一定的認識了,其實很容易我們就能夠想出,當兩個頂點的根節點相同時,就代表新增了這一條邊後會出現環路。這很好解釋,如果兩個頂點的根節點是相同的,代表這兩個頂點已經是連通的了,對於已經連通的兩個頂點,再新增一條邊,必然會產生環路。
第二條呢?
圖中的邊數,我們可以在每次進行真正合併操作之前(也就是,在確認兩個待合併的頂點的根節點不相同時)進行記錄。然後頂點數,也就是整個合併過程中參與進來的頂點個數了,可以使用乙個布林陣列來進行記錄,出現後將相應位置設為true,最後進行一輪統計即可。
筆記 並查集
不管後面寫了啥,一定要把最重要的寫在前面 總記不住 使用陣列表示並查集 int father n father i 表示元素i的父親結點 初始情況下,每個元素都是單獨的集合,因此其父結點是自己,這在並查集中被稱為reflexive for int i 1 i n i 乙個集合中只有乙個根結點,因此反...
並查集 並查集
本文參考了 挑戰程式設計競賽 和jennica的github題解 陣列版 int parent max n int rank max n void init int n int find int x else void union int x,int y else 結構體版 struct node ...
關於並查集的總結
參考了這個部落格的內容,學到了很多啊,特別是給出的這個例子很形象。然後就是這個並查集的模版了 總結歸納就是 int pre 1000 int find int x 路徑壓縮 return r void join int x,int y 當然具體題目有具體的改變,不過基本就是這樣了,會使用即可了。對於...