我以前學的是假的並查集;
這個題目有很明顯的歸屬關係,可一用並查集搞一搞
~~~~;
普遍來說有兩種方法;
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 的罪犯被關押在同一監獄,他們...