此題按照《挑戰程式設計競賽(第2版)》p89的解法,不容易想到,但想清楚了**還是比較直觀的。
並查集模板(包含了記錄高度的rank陣列和查詢時狀態壓縮)
1並查集實現const
int max_n=50002*3;2
intpar[max_n];
3int
rank[max_n];4//
初始化,根為自身,高度為0
5void init(int
scab)612
}13//查詢,途徑的所有結點都直接連到根上
14int find(int
x)15
19//
合併,把短鏈連線到長鏈上,保持結點高度的相對關係
20int unite(int x,int
y)21
26 par[y]=x;
27if(rank[x]==rank[y]) rank[x]++;
28return1;
29 }
並查集是用於維護「屬於同一集合」的資料結構,然而這道題的「屬於同一集合」並不指「是同類」,而是指「這幾個情況若發生必然同時發生」。
我們從理解題意開始:
有n只動物,分別編號為1,2,...,n。所有動物屬於a,b,c類中的一種,類之間有天然的a**,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
想清楚了道理,**就比較好理解了。注意由於從始至終只知道相對關係,同時維護了三種可能,所以判斷矛盾的時候任選一種判斷就可以了。
1oj執行結果如下:intmain()215
if(d==1
)16 25}
26else
if(d==2)27
38}39}
40 printf("
%d\n
",ans);
41return0;
42 }
這道題使我對並查集有了新的認識,想清楚「同屬乙個集合」代表什麼很重要,不一定就是題目限定的「屬於同一種」。
分析問題的難度有時會大於程式設計的難度,如果說**能力可以通過刷題習得,那麼分析問題的能力真的需要足夠的知識儲備和一些「創造性思維」了。
POJ 1182 食物鏈 並查集
此題利用並查集解決。對於每只動物i建立3個元素i a,i b,i c,並用這3 n個元素建立並查集。1 i x表示 i屬於種類x 2 並查集你的每一組表示組內所有元素代表的情況同時發生或不發生。對於每一條資訊,只需要按照下列操作即可 1.第一種 x,y同類,合併x a和y a x b和y b x c...
POJ 1182 食物鏈 (並查集)
食物鏈time limit 1000ms memory limit 10000k total submissions 48713 accepted 14202 description 動物王國中有三類動物a,b,c,這三類動物的食物鏈構成了有趣的環形。a吃b,b吃c,c吃a。現有n個動物,以1 n編...
POJ 1182 食物鏈(並查集)
description 動物王國中有三類動物a,b,c,這三類動物的食物鏈構成了有趣的環形。a吃b,b吃c,c吃a。現有n個動物,以1 n編號。每個動物都是a,b,c中的一種,但是我們並不知道它到底是哪一種。有人用兩種說法對這n個動物所構成的食物鏈關係進行描述 第一種說法是 1 x y 表示x和y是...