POJ 1182 食物鏈(兩種解法)

2021-09-25 19:52:00 字數 2906 閱讀 7401

題目描述:

動物王國中有三類動物a,b,c,這三類動物的食物鏈構成了有趣的環形。a**, b吃c,c吃a。

現有n個動物,以1-n編號。每個動物都是a,b,c中的一種,但是我們並不知道它到底是哪一種。

有人用兩種說法對這n個動物所構成的食物鏈關係進行描述:

第一種說法是"1 x y",表示x和y是同類。

第二種說法是"2 x y",表示x吃y。

此人對n個動物,用上述兩種說法,一句接一句地說出k句話,這k句話有的是真的,有的是假的。當一句話滿足下列三條之一時,這句話就是假話,否則就是真話。

1) 當前的話與前面的某些真的話衝突,就是假話;

2) 當前的話中x或y比n大,就是假話;

3) 當前的話表示x吃x,就是假話。

你的任務是根據給定的n(1 <= n <= 50,000)和k句話(0 <= k <= 100,000),輸出假話的總數。

input

第一行是兩個整數n和k,以乙個空格分隔。

以下k行每行是三個正整數 d,x,y,兩數之間用乙個空格隔開,其中d表示說法的種類。

若d=1,則表示x和y是同類。

若d=2,則表示x吃y。

output

只有乙個整數,表示假話的數目。

sample input

100 7

1 101 1

2 1 2

2 2 3

2 3 3

1 1 3

2 3 1

1 5 5

sample output3

思路分析:這道題一開始的想法是用帶權並查集,後來發現至少需要三組陣列,每次還要分很多情況,太麻煩了,於是看大佬的部落格,發現並查集居然還能這樣用!之前一直是想著假設一開始的是a類,然後後來者根據情況對應之。思維侷限。完全不需要確定誰具體是a還是bc呀,只需要知道他們之間的關係就行

大佬思路如下:

我們不關心小動物具體是abc,只關心他們之間的關係,所以每個動物都有abc類三種可能,三種可能表示的對應關係是一樣的,我們判斷關係的時候只需要假設都是a類即可。

開三倍空間,前50000表示a類,中間50000表示b類,後50000表示c類。跨類別同祖先表示捕食關係,同類別同祖先表示同類關係。如此一來,下標就能表示捕食關係,比如如果a中有1,b中有2,那麼就可以表示1吃2。單純下標表示捕食關係是不夠的,比如123456,既能表示1吃2也能表示2吃1。

所以再用並查集的父子關係來表示捕食關係,**食者祖先是捕食者。這樣的話123456就成了153153,a中的1和b中的2都返回1,所以a中的1和b中的2等價,僅表示1吃2

這道題的歸併是有邏輯先後的,不能壓縮路徑!

如果x,y同類關係的話,就將abc類裡x,y都合併。

例子:aaa

bbbc

cc12

3456

789初始狀態aa

abbb

ccc1

22n+245

278n+2

輸入 2吃3aa

abbb

ccc1

2n+1

2n+241

27n+1n+2

輸入 1吃2

此時,a1的祖先是1,b3的祖先是,2 -> 2n+1 -> 7,7在c類,而1在a類,所以3吃1

#include #include #include #include #include #include using namespace std;

int tree[150050];

int find(int x)

int same(int a,int b)

void unite(int a,int b)

}int main()

while(k--)

if(t==1)

else

}if(t==2)

else

}// printf("%d|%d|%d|%d|%d|%d|%d|%d|%d\n",tree[1],tree[2],tree[3],tree[n+1],tree[n+2],tree[n+3],tree[2*n+1],tree[2*n+2],tree[2*n+3]);

// printf("%d*\n",ans);

}printf("%d\n",ans);

}

解法二:

帶權並查集

本題目只需要知道相對關係,並不需要明確小動物具體是abc哪一類。而帶權並查集的權值可以表示與父節點的相對關係,所以可以用帶權並查集解這道題。

tree[y]=x,表示y和x有關係,同乙個根節點表示在同乙個已知關係裡,也就是說在同一條食物鏈中。value為0表示某節點與父節點同類關係,1表示吃父節點,2表示被父節點吃。我們只需要知道每個節點和父節點的關係,在路徑壓縮的時候層層向上修改即可

權值更新和判斷可以擬幾個例子歸納出來

#include #include #include #include #include #include using namespace std;

int n,k,d,x,y,ans;

int tree[50010];

int value[50010];

int find(int x)

return tree[x]=tmp;

}int main()

while(k--)

int rx=find(x);

int ry=find(y);

if(d==1)

else }}

if(d==2)

else }}

}printf("%d\n",ans);

return 0;

}

帶權並查集

Poj 1182 食物鏈 (兩種思路)

思路 對每個節點維護其到根節點的偏移量 偏移量代表種類關係 par x 表示x的根節點,rel x 表示x與根節點的偏移量。rel x 0表示x與根節點為同類,1表示根節點吃x,2代表x吃根節點。同類 不同類時,如何判斷關係是否矛盾以及如何合併兩頂點所在的集合。include include inc...

POJ 1182 食物鏈 Union Find題解

union find就是所謂的並查集。本題做的很無語,最後發現居然是輸入搞錯,一直wa。不能使用迴圈接受輸入,否則是wa的,氣死人,浪費那麼多時間就為了這個。難點 1 構建關係樹 2 構建公式 3 快速更新公式 要抽象思維出什麼對應什麼的關係和上面是逆關係,就是利用0,1,2構建出父子節點之間的關係...

POJ 1182 食物鏈 解題報告

食物鏈 time limit 1000ms memory limit 10000k total submissions 70529 accepted 20875 description 動物王國中有三類動物a,b,c,這三類動物的食物鏈構成了有趣的環形。a吃b,b吃c,c吃a。現有n個動物,以1 n...