並查集 洛谷P1525 關押罪犯

2021-07-27 14:53:48 字數 1963 閱讀 8811

我以前學的是假的並查集;

這個題目有很明顯的歸屬關係,可一用並查集搞一搞

~~~~;

普遍來說有兩種方法;

1.權值並查集;

2.拆點並查集;

我們乙個乙個來;

當然他們的共同條件就是要先把邊按權值遞減排序,不斷加入,直到無法避免矛盾,那麼直接輸出答案;

權值並查集

這個很難解釋啊;

我們定義如果x,y相連,那麼代表他們在不同的監獄;

所以我們不難得出一種方法;

我們讀入x,y,就先灌水看看x,y的距離;

如果是奇數那麼是可以,偶數就不可以;

如果無法聯通就加一條邊;

這樣n^2,太虛了;

那麼我們是否可以壓縮路徑變成並查集呢?

我們每次連邊時,不要慌,去找到他們的祖先;

盡可能的去連他們的祖先,因為這樣方便路徑壓縮;

其實我們鏈結x,y就保證了x,y的距離時奇數,是可行的;

但是如果x,y祖先去連邊,也許x,y的距離就變成了偶數,x,y就矛盾了;

那我們怎麼辦呢?;

讓邊帶權值,我們判斷時不是簡單的算距離,而是算兩個點之間所有邊的權值;

這樣的話,我們在鏈結x,y,的祖先前;先算出x到x祖先的距離,xx

y到y祖先的距離yy;

假如xx+yy是偶數,那麼兩個祖先的邊要有權值1,代表兩祖先不在用乙個監獄;要是奇數,那麼兩個祖先的邊無權值,即0,說明兩個祖先同一監獄;

#include

#include

#include

#include

#include

#include

#include

#define ll long long

using

namespace

std;

struct csa[100001];

int fa[100001],g[100001];

int n,m,x,y,z,ans;

bool cmp(cs a,cs b)

int get(int x)

void merge(int x,int y)

int main()

else;

else merge(x,y);

}printf("0");

}

拆點並查集

就是拆點;

我們把乙個點x變成x,和x+n

代表x點在第乙個監獄和第二個監獄;

然後讀入x,y

如果x,y在同乙個集合,直接退出;

當x,y在同乙個集合,x+n,y+n也一定在同乙個集合;

不然建兩條邊;

x—n+y;

y—n+x;

表示x,n+y在乙個集合;

y,n+x,在乙個集合;

其實就是表示x,y不在同乙個集合;

這樣 讀入為

1 2、、、、、、2 3那麼這樣建圖,1,3就在乙個集合了

#include

#include

#include

#include

using

namespace

std;

struct csa[100001];

int fa[40001];

int n,m,x,y,z;

bool cmp(cs x,cs y)

int get(int x)

void merge(int x,int y)

int main()

merge(y,x+n);

merge(x,y+n);

}printf("0");

}

P1525 關押罪犯 並查集

評測記錄 有n個罪犯,罪犯有些關係,就是 i j,c i,j,c 表示罪犯i和罪犯j在同乙個監獄會造成c的破壞,有兩座監獄,要求分配的使得最大的破壞最小。先按照c排序,然後就從大到小處理直到無法處理。我們可以用並查集表示在乙個監獄中,然後用敵人的敵人是朋友來合併。記錄每個罪犯的敵人的根,然後每次合併...

並查集 P1525 關押罪犯

s城現有兩座監獄,一共關押著n名罪犯,編號分別為1 n。他們之間的關係自然也極不和諧。很多罪犯之間甚至積怨已久,如果客觀條件具備則隨時可能爆發衝突。我們用 怨氣值 乙個正整數值 來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之間的積怨越多。如果兩名怨氣值為 c 的罪犯被關押在同一監獄,他們...

並查集 P1525 關押罪犯

s城現有兩座監獄,一共關押著n名罪犯,編號分別為1 n。他們之間的關係自然也極不和諧。很多罪犯之間甚至積怨已久,如果客觀條件具備則隨時可能爆發衝突。我們用 怨氣值 乙個正整數值 來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之間的積怨越多。如果兩名怨氣值為 c 的罪犯被關押在同一監獄,他們...