【noip 2010】 關押罪犯
描述
S城現有兩座監獄,一共關押著N名罪犯,編號分別為1~N。他們之間的關系自然也極不和諧。很多罪犯之間甚至積怨已久,如果客觀條件具備則隨時可能爆發沖突。我們用“怨氣值”(一個正整數值)來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之間的積怨越多。如果兩名怨氣值為c的罪犯被關押在同一監獄,他們倆之間會發生摩擦,並造成影響力為c的沖突事件。每年年末,警察局會將本年內監獄中的所有沖突事件按影響力從大到小排成一個列表,然後上報到S城Z市長那裏。公務繁忙的Z市長只會去看列表中的第一個事件的影響力,如果影響很壞,他就會考慮撤換警察局長。在詳細考察了N名罪犯間的矛盾關系後,警察局長覺得壓力巨大。他準備將罪犯們在兩座監獄內重新分配,以求產生的沖突事件影響力都較小,從而保住自己的烏紗帽。假設只要處於同一監獄內的某兩個罪犯間有仇恨,那麽他們一定會在每年的某個時候發生摩擦。那麽,應如何分配罪犯,才能使Z市長看到的那個沖突事件的影響力最小?這個最小值是多少?
輸入格式
輸入文件的每行中兩個數之間用一個空格隔開。
第一行為兩個正整數N和M,分別表示罪犯的數目以及存在仇恨的罪犯對數。
接下來的M行每行為三個正整數aj,bj,cj,表示aj號和bj號罪犯之間存在仇恨,其怨氣值為cj。
數據保證1<=aj<=bj<=N,0<=cj<=1000000000,且每對罪犯組合只出現一次。
輸出格式
輸出文件共1行,為Z市長看到的那個沖突事件的影響力。如果本年內監獄中未發生任何沖突事件,請輸出0
樣例輸入
4 6
1 4 2534 2 3 3512 1 2 28351 1 3 6618 2 4 1805 3 4 12884
樣例輸出
3512
限制
每個測試點1s
提示
分配方法:市長看到的沖突事件影響力是3512(由2號和3號罪犯引發)。其他任何分法都不會比這個分法更優。
對於30%的數據有N≤15。
對於70%的數據有N≤2000,M≤50000。
對於100%的數據有N≤20000,M≤100000。
題解
最簡單的方法還是並查集。開一個兩倍的並查集表示犯人的集合及其補集,排序按怨念從大到小往集合裏放,發現沖突直接輸出就可以了。
排序直接調用的<algorithm>中的 sort(a+1, a+n+1)。並查集是標準的一行式路徑壓縮,每次查找確認不沖突後分別放到對方的補集中。空間 O(2n),時間 O(m lg*n),其中 lg*n 最大為 5 效率很高,90分。
最後註意沒有沖突要輸出 0,這樣才能 100 分。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #define maxn 20005 6 #define maxm 100005 7 using namespace std; 8 int n,m,x,y,fa[2*maxn]; 9 struct sky{ 10 int a,b,c; 11 }e[maxm]; 12 bool cmp(sky p1,sky p2){ 13 return p1.c>p2.c; 14 } 15 int read(){ 16 int x=0,f=1;char ch=getchar(); 17 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} 18 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 19 return x*f; 20 } 21 int find(int x){ 22 if(fa[x]==x) return x; 23 else return fa[x]=find(fa[x]); 24 } 25 int main(){ 26 n=read(),m=read(); 27 for(int i=1;i<=m;i++) e[i].a=read(),e[i].b=read(),e[i].c=read(); 28 for(int i=1;i<=2*n;i++) fa[i]=i; 29 sort(e+1,e+m+1,cmp); 30 for(int i=1;i<=m;i++){ 31 x=find(e[i].a),y=find(e[i].b); 32 if(x==y){ 33 printf("%d",e[i].c); 34 return 0; 35 } 36 fa[y]=find(e[i].a+n); 37 fa[x]=find(e[i].b+n); 38 } 39 puts("0"); 40 return 0; 41 }
【noip 2010】 關押罪犯