wikioi-天梯-提高一等-并查集-1074:食物链
題目描述?Description
動(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中的一種,但是我們并不知道它到底是哪一種。
有人用兩種說法對(duì)這N個(gè)動(dòng)物所構(gòu)成的食物鏈關(guān)系進(jìn)行描述:
第一種說法是“1 X Y”,表示X和Y是同類。
第二種說法是“2 X Y”,表示X吃Y。
此人對(duì)N個(gè)動(dòng)物,用上述兩種說法,一句接一句地說出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 Description
第一行是兩個(gè)整數(shù)N和K,以一個(gè)空格分隔。
以下K行每行是三個(gè)正整數(shù)D,X,Y,兩數(shù)之間用一個(gè)空格隔開,其中 D 表示說法的種類。
若D=1,則表示X和Y是同類。
若D=2,則表示X吃Y。
輸出描述?Output Description
只有一個(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
數(shù)據(jù)范圍及提示?Data Size & Hint
輸入文件??
?對(duì)7句話的分析 100 7
1 101 1 假話
2 1 2 ? 真話
2 2 3 ? 真話
2 3 3 ? 假話
1 1 3 ? 假話
2 3 1 ? 真話
?1 5 5 ? 真話
NOI 2001 食物鏈(eat)
類型:圖論 ?難度:3
題意:題面說的很明白,見題目
分析:比1069要難一些的并查集題目,對(duì)于每個(gè)種類i,用fa[i]記錄其并查集的父節(jié)點(diǎn)(同類),用eat[i]記錄它吃誰,用eaten[i]記錄它被誰吃,這樣記錄了一個(gè)3物種循環(huán),根據(jù)題目分兩種情況:
(1)X和Y是同類,此時(shí),若X吃Y或Y吃X(除了同類只有這兩種關(guān)系,因?yàn)橹挥腥齻€(gè)物種),則矛盾,結(jié)果累加;
若X和Y不存在關(guān)系,則需要將X和Y合并為同類,此時(shí),不僅要合并X和Y,還要合并eat[X],eat[Y]和eaten[X],eaten[Y];
此外,設(shè)合并后X和Y這類的根節(jié)點(diǎn)為r,還要更新r的eat和eaten值,eat[r]的eat和eaten值,eaten[r]的eat和eaten值,保證信息保留完整
(2)X吃Y,此時(shí),X和Y同類或Y吃X,則矛盾,結(jié)果累加;
若X和Y不存在關(guān)系,需要合并eat[X]和Y,eaten[Y]和X,eat[Y]和eaten[X];
和(1)類似,設(shè)合并后eat[X]和Y這類的根節(jié)點(diǎn)為r,還要更新r的eat和eaten值,eat[r]的eat和eaten值,eaten[r]的eat和eaten值,保證信息保留完整
注意:由于每類的eat和eaten信息都必須存儲(chǔ)在根節(jié)點(diǎn)中,但是根節(jié)點(diǎn)eat和eaten指向的節(jié)點(diǎn)不一定是那一類的根節(jié)點(diǎn),所以寫了兩個(gè)findeat和findeaten函數(shù),作用是:先找到當(dāng)前集合的根節(jié)點(diǎn),然后找到根節(jié)點(diǎn)的eat或eaten節(jié)點(diǎn)i,再找到這個(gè)i在它的集合中的根節(jié)點(diǎn),就能保證eat和eaten關(guān)系都操作在根節(jié)點(diǎn)層面。
代碼:
#include<iostream> #include<cstdio> #include<cstring> using namespace std;int fa[50010],eat[50010],eaten[50010];int mfind(int a) {if(fa[a] != a) fa[a] = mfind(fa[a]);return fa[a]; }int mmerge(int a,int b) {if(!a) return b;if(!b) return a;return (fa[mfind(a)] = mfind(b)); }int findeat(int a) {int ra = mfind(a);int tmp = eat[ra];if(!tmp) return tmp;int rf = mfind(tmp);eat[ra] = rf;return rf; }int findeaten(int a) {int ra = mfind(a);int tmp = eaten[ra];if(!tmp) return tmp;int rf = mfind(tmp);eaten[ra] = rf;return rf; }int main() {int n,k;scanf("%d%d",&n,&k);for(int i=0; i<=n; i++){fa[i] = i;}memset(eat,0,sizeof(eat));memset(eaten,0,sizeof(eaten));int a,b,c;int ans = 0;while(k--){scanf("%d%d%d",&a,&b,&c);if(b>n || c>n || b<=0 || c<=0){ans++;continue;}int rb = mfind(b);int rc = mfind(c);int eb = findeat(rb);int ec = findeat(rc);int etb = findeaten(rb);int etc = findeaten(rc);if(a==1){if(eb==rc || ec==rb || etc==rb || etb==rc){ans++;continue;}fa[rb] = rc;eat[rc] = mmerge(eb,ec);eaten[rc] = mmerge(etb,etc);if(ec) {eaten[ec] = rc;eat[ec] = eaten[rc];}if(etc) {eat[etc] = rc;eaten[etc] = eat[rc];}}else{if(rb==rc || ec==rb || etb==rc){ans++;continue;}eat[rb] = mmerge(eb,rc);eaten[rc] = mmerge(etc,rb);eat[rc] = eaten[rb] = mmerge(etb,ec);int d = eat[rc];if(d){eat[d] = rb;eaten[d] = rc;}}}cout<<ans<<endl; }
總結(jié)
以上是生活随笔為你收集整理的wikioi-天梯-提高一等-并查集-1074:食物链的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 软考DFD图
- 下一篇: Cytoscape安装及使用