日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

poj1182(食物链)续

發(fā)布時(shí)間:2024/4/15 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 poj1182(食物链)续 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

動(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)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。