poj1182(食物链)续
意
動(dòng)物王國(guó)中有三類動(dòng)物A,B,C,這三類動(dòng)物的食物鏈構(gòu)成了有趣的環(huán)形。A吃B, B吃C,C吃A。
現(xiàn)有N個(gè)動(dòng)物,以1-N編號(hào)。每個(gè)動(dòng)物都是A,B,C中的一種,但是我們并不知道它到底是哪一種。
有人用兩種說(shuō)法對(duì)這N個(gè)動(dòng)物所構(gòu)成的食物鏈關(guān)系進(jìn)行描述:
第一種說(shuō)法是"1 X Y",表示X和Y是同類。
第二種說(shuō)法是"2 X Y",表示X吃Y。
此人對(duì)N個(gè)動(dòng)物,用上述兩種說(shuō)法,一句接一句地說(shuō)出K句話,這K句話有的是真的,有的是假的。當(dāng)一句話滿足下列三條之一時(shí),這句話就是假話,否則就是真話。
1)當(dāng)前的話與前面的某些真的話沖突,就是假話;
2)當(dāng)前的話中X或Y比N大,就是假話;
3)當(dāng)前的話表示X吃X,就是假話。
你的任務(wù)是根據(jù)給定的N(1 <= N <= 50,000)和K句話(0 <= K <= 100,000),輸出假話的總數(shù)。
Input
第一行是兩個(gè)整數(shù)N和K,以一個(gè)空格分隔。
以下K行每行是三個(gè)正整數(shù) D,X,Y,兩數(shù)之間用一個(gè)空格隔開,其中D表示說(shuō)法的種類。
若D=1,則表示X和Y是同類。
若D=2,則表示X吃Y。
Output
只有一個(gè)整數(shù),表示假話的數(shù)目。
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 Output
3
解題思路這一題的基本思路是對(duì)每句話判斷真假,同時(shí)記錄由真話構(gòu)成的食物鏈的結(jié)構(gòu),進(jìn)行統(tǒng)計(jì),最后輸出統(tǒng)計(jì)結(jié)果。
關(guān)鍵是對(duì)每句話的判斷上。
可以看出3個(gè)物種之間的關(guān)系是相對(duì)的,對(duì)稱的,所以要記錄的是動(dòng)物間的關(guān)系,而非它們是什么物種。如果我們把相互間可以確定捕食關(guān)系的動(dòng)物放在一個(gè)集合中,那么實(shí)際上在處理過(guò)程中我們可能會(huì)得到多個(gè)集合,同時(shí)會(huì)出現(xiàn)需要將兩個(gè)集合合并的情況(例如a屬于集合A,b屬于集合B,當(dāng)a,b的關(guān)系確定時(shí),集合A,B就需要合并為一個(gè)集合),由這種動(dòng)態(tài)處理集合的情況不難聯(lián)想到并查集。
利用并查集來(lái)存儲(chǔ)已知的捕食結(jié)構(gòu)。當(dāng)f[a]=a時(shí),表示a是本集合的根結(jié)點(diǎn),f[a]=b表示a,b間有已經(jīng)確定的捕食關(guān)系。這樣想知道a,b間的捕食關(guān)系只要找到a,b的根結(jié)點(diǎn)即可,a,b有相同根結(jié)點(diǎn)則可通過(guò)邏輯判斷確定a,b關(guān)系,a,b有不同根節(jié)點(diǎn),說(shuō)明a,b關(guān)系尚未確定。這樣我們還需要一個(gè)和f[n]對(duì)應(yīng)的存儲(chǔ)結(jié)構(gòu) vec[n]用以存儲(chǔ)f[a]與其父結(jié)點(diǎn)的捕食關(guān)系。由于關(guān)系都是相對(duì)的,而且有向的,我們可以以向量的思想來(lái)確定。
我們以vec[a]=0表示a結(jié)點(diǎn)與其父結(jié)點(diǎn)是同類,vec[a]=-1表示a捕食其父結(jié)點(diǎn),vec[a]=1表示a被其父結(jié)點(diǎn)捕食。首先構(gòu)造函數(shù)getf(a)來(lái)得到a的根結(jié)點(diǎn),構(gòu)造getv(a)來(lái)得到a與其根結(jié)點(diǎn)的關(guān)系向量。
?
當(dāng)?shù)玫捷斎雂 a b時(shí),若ab有相同根結(jié)點(diǎn),則如上圖,不難有d-1==getv(b)-getv(a)時(shí)是真話。
同樣,a,b有不同根結(jié)點(diǎn)時(shí),這句話為真,可以確定兩根結(jié)點(diǎn)的關(guān)系,a到b的關(guān)系向量為:
?getv(b)-(d-1)-getv(a);
以上就是以向量和并查集來(lái)考慮本題的思路。
參考: http://hi.baidu.com/bobo__bai/item/fbf57d110b72650fb88a1a09
參考代碼:代碼中用pa數(shù)組表示每個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn),ch數(shù)組表示節(jié)點(diǎn)與它的父節(jié)點(diǎn)的關(guān)系,即向量的關(guān)系。
#include <stdio.h>
#include <string.h>
const int MAXN = 50005;
int pa[MAXN], ch[MAXN];
int n, k, lies;
void init_set()
{
??? int i;
??? for (i = 0; i < MAXN; i++) pa[i] = i;
??? memset(ch, 0, sizeof(int)*MAXN);
??? lies = 0;
}
?
int find_set(int x)
{
??? if (pa[x] == x)
??????? return x;
??? int xt = find_set(pa[x]);
??? ch[x] = (ch[x] + ch[pa[x]] + 3) % 3;
??? pa[x] = xt;
??? return xt;
}
void union_set(int d, int x, int y)? // d, 表示 x 對(duì) y 的關(guān)系,0, 同類,1,x吃y
{
??? if (x > n || y > n )? {
??????? ++lies;
??????? return;
??? }
??? int fx = find_set(x);
??? int fy = find_set(y);
??? if (fx == fy)? {
??????? if ((ch[x] - ch[y] + 3) % 3 != d) {
??????????? ++lies;
??????? }
??? } else {
??? ?ch[fx] = (d + ch[y] - ch[x] + 6) % 3;
pa[fx] = fy;
}
}
int main()
{
??? int i, d, x, y;
??? scanf("%d %d\n", &n, &k);
??? init_set();
??? for (i = 0; i < k; i++) {
??????? scanf("%d %d %d\n", &d, &x, &y);
??????? union_set(d - 1, x, y);
??? }
??? printf("%d", lies);
??? return 0;
}
轉(zhuǎn)載于:https://www.cnblogs.com/13224ACMer/p/4434801.html
總結(jié)
以上是生活随笔為你收集整理的poj1182(食物链)续的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: html5中在canvas上绘图
- 下一篇: 29. Divide Two Integ