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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

poj1182(加权值的并查集)

發(fā)布時間:2025/4/16 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 poj1182(加权值的并查集) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Description

動物王國中有三類動物A,B,C,這三類動物的食物鏈構(gòu)成了有趣的環(huán)形。A吃B, B吃C,C吃A。?
現(xiàn)有N個動物,以1-N編號。每個動物都是A,B,C中的一種,但是我們并不知道它到底是哪一種。?
有人用兩種說法對這N個動物所構(gòu)成的食物鏈關(guān)系進行描述:?
第一種說法是"1 X Y",表示X和Y是同類。?
第二種說法是"2 X Y",表示X吃Y。?
此人對N個動物,用上述兩種說法,一句接一句地說出K句話,這K句話有的是真的,有的是假的。當(dāng)一句話滿足下列三條之一時,這句話就是假話,否則就是真話。?
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

第一行是兩個整數(shù)N和K,以一個空格分隔。?
以下K行每行是三個正整數(shù) D,X,Y,兩數(shù)之間用一個空格隔開,其中D表示說法的種類。?
若D=1,則表示X和Y是同類。?
若D=2,則表示X吃Y。

Output

只有一個整數(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

轉(zhuǎn)載以下博客的文字:

鏈接入口:http://www.cnblogs.com/dongsheng/archive/2013/06/12/3133188.html


覺得這個博客寫的挺清晰,解釋的挺詳細(xì)的,自己多加思考就更清晰了。

大體思想:

1、如果兩個物種有聯(lián)系,不管是吃,被吃還是同類,它們之間應(yīng)該是有一條徑路可達(dá)的,
也就是它們在一個合集中。
2、如果a,b有關(guān)系,b,c有關(guān)系,那么a,c之間的關(guān)系式可以通過兩者的關(guān)系推出來的。

OK,下面圍繞著上面的兩個思想來逐一拆分。
首先就是怎么把有關(guān)系的物種放到同一個合集中去,這就要需用到并查集了。每一次入輸d,x,y,
也就是相當(dāng)于x,y之間有一條權(quán)為d的徑路。先忽略這個權(quán)值,直接斟酌路徑,那并查集的路徑建立就
不用我說了。一個parent數(shù)組,parent[i]表現(xiàn)從parent[i]到i有一條徑路。OK,那不同的物食圈就構(gòu)
成了一個連通區(qū)域。每個連通區(qū)域都有一個根點節(jié)。

下面斟酌怎么處理這個權(quán)
先說點數(shù)學(xué)的貨色,任何一種偏序關(guān)系都足滿自反、對稱、傳遞。
自反:自己跟自己滿足偏序關(guān)系。
對稱:a,b的偏序關(guān)系為r,則b,a的偏序關(guān)系為~r.表現(xiàn)求反。
傳遞:a,b的偏序關(guān)系為r1,b,c的偏序關(guān)系為r2,a,c的偏序關(guān)系為r1+r2.

為了便利,用一個relation數(shù)組來維護這個權(quán)值。relation[i]表現(xiàn)的是i在所的連通區(qū)域的
根點節(jié)到i的關(guān)系。先略忽這個關(guān)系數(shù)組的維護過程,把團體的思緒理清晰。如果有兩個物種加進來,
就有兩種情況,要么它們在同一個連通集里頭。要么不在同一個連通集里頭。

一、兩者在同一個連通集里頭:
1、新加的關(guān)系表明x,y是同類,那么它們兩個分別到連通區(qū)域根點節(jié)的關(guān)系應(yīng)該是一樣的,
要不就矛盾了。(記為case1)
2、如果新加的關(guān)系表明x,y不是同類,那么在當(dāng)前參加y,x相對根節(jié)點的關(guān)系和x本來相對根點節(jié)的
關(guān)系應(yīng)該是不變的,否則就矛盾了。(記為case2)

二、兩者在不同的連通集里頭:就直接連接兩個連通集就能夠了。(記為case3)

路徑壓縮處理:
由于后來物種會越來越多,我們不希望食物鏈拉的很長,所以會盡可能的讓全部的點節(jié)都直接和根節(jié)點
相連。這樣整個連通的圖就有點呈現(xiàn)出星形。

怎么維護關(guān)系數(shù)組:
數(shù)組里頭的每個元素的取值要么是0(同類),要么是1(父吃子),要么是2(子吃父)。至于為什么要
這么設(shè)置(因為題目中1表示同類,而我們定義0表示同類,相對都應(yīng)該減一,所以題目中的2表示父吃子在我們這里
應(yīng)該是2-1=1,,1表示父吃子),參考一另篇博客http://blog.csdn.net/c0de4fun/article/details/7318642,
這里是不能隨便定義的。設(shè)前面的數(shù)據(jù)我已經(jīng)處理好了,現(xiàn)在要處理d,x,y.為了敘說的便利,
記relation[x]為x根->x.那么在現(xiàn)就有三種情況:
case1:(同一個集合且同類)
這種情況x根與y根雷同。如果x根->x與y根->y不同,表明x,y不是同類,與d=1矛盾。
case2:(同一個集合但不同類)
這種情況x根與y根雷同。如果參加y之后,(x根->x) = (x根(即y根)->y + y->x),如果新求出來
的關(guān)系與本身已有的x根->x的關(guān)系不同,則矛盾。
case3:(在不同集合中)
這種情況x根與y根不同。由于這里添加的是x到y(tǒng)的一條有向邊。將y根的父點節(jié)設(shè)置為x根,更新y根父點
節(jié)到x根的關(guān)系,即x根->y根=x根->x+x->y+y->y根,由于這里都是有向邊,所以更新關(guān)系的時候注意關(guān)
系的方向。這里需要注意,我們只更新了兩個根之間的關(guān)系,x根與原來的y所在的連通區(qū)域里頭的節(jié)點
的關(guān)系都沒有更新,這就是為什么要在一開始判斷之前就要調(diào)用Find函數(shù),更新每個點節(jié)到其根點節(jié)的
關(guān)系。

初始條件:
有了這個遞推,就好辦了。初始條件parent就是并查集一般的初始條件,父點節(jié)于等自己。由于初始的
時候父節(jié)點是自己,當(dāng)然自己跟自己的關(guān)系肯定是同類咯,也就是relation[i]=0


#include <iostream> #include<algorithm> #include<stdio.h> using namespace std; const int MAXN = 100010;int f[MAXN],rela[MAXN];int ff(int x) {int tem=f[x];if(tem!=x)f[x]=ff(tem),rela[x]=(rela[x]+rela[tem])%3;return f[x]; } int main() {int n,m,d,x,y;scanf("%d%d",&n,&m);for(int i=0;i<=MAXN;i++)f[i]=i,rela[i]=0;int s=0;while(m--){scanf("%d%d%d",&d,&x,&y);if(x > n || y > n){s++;continue;}if(d == 2 && x == y){s++;continue;}int tem1=ff(x),tem2=ff(y);if(tem1==tem2){if(d==1&&rela[x]!=rela[y])s++;else if(d==2&&rela[x]!=(rela[y] + 2)%3)s++;}else{f[tem2]=tem1;rela[tem2]=(rela[x]+(d-1)+(3-rela[y]))%3;}}printf("%d\n",s);return 0; }

轉(zhuǎn)載于:https://www.cnblogs.com/martinue/p/5490542.html

總結(jié)

以上是生活随笔為你收集整理的poj1182(加权值的并查集)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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