天天看點

【POJ 1182 食物鍊】并查集

此題按照《挑戰程式設計競賽(第2版)》P89的解法,不容易想到,但想清楚了代碼還是比較直覺的。

并查集模闆(包含了記錄高度的rank數組和查詢時狀态壓縮)

【POJ 1182 食物鍊】并查集
【POJ 1182 食物鍊】并查集

并查集實作

并查集是用于維護“屬于同一集合”的資料結構,然而這道題的“屬于同一集合”并不指“是同類”,而是指“這幾個情況若發生必然同時發生”。

我們從了解題意開始:

有N隻動物,分别編号為1,2,...,N。所有動物屬于A,B,C類中的一種,類之間有天然的A吃B,B吃C,C吃A的關系。

按如下兩種格式順序給出共K條資訊(隻表達了相對關系):

1 x y: x,y是同類

2 x y: x吃y

每條資訊若不符合常理(編号大于N,或自己吃自己)或與已有資訊沖突,則為錯誤。

問這K條資訊有幾條錯誤?

由于A,B,C之間的吃與被吃關系構成一個循環,是以三類的等級關系根本上也是相對的,那麼每條資訊都可以翻譯成三種可能的實際情況。同時維護這三種可能

,就需要為每個動物x配置設定三個數組元素,分别表示x是A,x是B,x是C這三個事件。

同屬一個集合的事件意味着“若發生必然同時發生”。

并查集需要用一個數組存儲每個元素“屬于哪一集合”,那麼可以開一個長度為N*3的數組,用x,x+N,x+N*2分别表示x是A,x是B,x是C。

表示x與y是同類,需要維護這三種可能

unite(x,y);        //x,y都是A

unite(x+n,y+n);     //x,y都是B

unite(x+2*n,y+2*n); //x,y都是C

表示x吃y,需要維護這三種可能

unite(x,y+n);    //x是A,y是B

unite(x+n,y+2*n);  //x是B,y是C

unite(x+2*n,y);  //x是C,y是A

想清楚了道理,代碼就比較好了解了。注意由于從始至終隻知道相對關系,同時維護了三種可能,是以判斷沖突的時候任選一種判斷就可以了。

OJ運作結果如下:

【POJ 1182 食物鍊】并查集

這道題使我對并查集有了新的認識,想清楚“同屬一個集合”代表什麼很重要,不一定就是題目限定的“屬于同一種”。

分析問題的難度有時會大于程式設計的難度,如果說代碼能力可以通過刷題習得,那麼分析問題的能力真的需要足夠的知識儲備和一些“創造性思維”了。