1. 程式人生 > >【NOIP2010】關押罪犯

【NOIP2010】關押罪犯

color name nbsp cli c代碼 u+ math get www

本題在洛谷上的鏈接:https://www.luogu.org/problemnew/show/P1525


應該說這道題不算太難,但挺考察代碼實現能力。首先我們應該是本著貪心的原則,讓怨氣值大的罪犯盡量分開,這樣就牽扯到將n個點劃分成兩部分的問題。做法有兩種,並查集或二分答案+二分圖染色。值得一提的是並查集,這裏get到了一個新技能:補集。

一開始,我判斷的方法是,將不能在一起的罪犯加入到一個並查集,如果遇到沖突(兩個罪犯原先就在一個並查集裏)則為判定失敗,這樣只有60分。哪裏不對呢?舉個簡單的例子,A和B不能在一起,B和C不能在一起,C和D不能在一起,按照上面的方法,A和D也不能在一起,但實際上A和D可以在一起,這牽扯到兩個點之間隔著奇數個點還是偶數個點。

然後看到dalao題解裏有種方法是使用補集,就是把不能和某個罪犯在一起的罪犯放到一起,因為只有兩個牢房,如果放到一起的罪犯不能在一起,這就是真的沖突了。

技術分享圖片
 1 #include<cstdio>
 2 #include<cctype>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 inline int get_num() {
 8     int num;char c;
 9
while((c=getchar())==\n||c== ||c==\r); 10 num=c-0; 11 while(isdigit(c=getchar())) num=num*10+c-0; 12 return num; 13 } 14 const int maxn=2e4+5,maxm=1e5+5; 15 int n,m,fa[2*maxn],d[maxn]; 16 struct edge { 17 int u,v,w; 18 bool operator < (const edge& rhs) const
{ 19 return w>rhs.w; 20 } 21 } E[maxm]; 22 int f(int i) { 23 if(fa[i]==i) return i; 24 return fa[i]=f(fa[i]); 25 } 26 int main() { 27 n=get_num();m=get_num(); 28 for(int i=1;i<=m;++i) 29 E[i].u=get_num(),E[i].v=get_num(),E[i].w=get_num(); 30 sort(E+1,E+m+1); //將邊按降序排序 31 for(int i=1;i<=2*n;++i) fa[i]=i; 32 for(int i=1;i<=m;++i) { 33 int u=E[i].u,v=E[i].v; 34 if(f(u)==f(v)) { 35 printf("%d",E[i].w); 36 return 0; 37 } 38 fa[fa[u]]=fa[f(v+n)]; //將不能和v在一起的和v+n放在一起 39 fa[fa[v]]=fa[f(u+n)]; //同上 40 } 41 printf("0"); 42 return 0; 43 }
AC代碼

【NOIP2010】關押罪犯