【NOIP2010提高組】關押罪犯
題目背景
NOIP2010提高組試題
題目描述
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≤1,000,000,000,且每對罪犯組合只出現一次。
輸出格式
輸出共 1 行,為Z市長看到的那個衝突事件的影響力。如果本年內監獄中未發生任何衝突事件,請輸出 0 。
樣例資料 1
輸入
4 6 1 4 2534 2 3 3512 1 2 28351 1 3 6618 2 4 1805 3 4 12884
輸出
3512
備註
【樣例說明】 罪犯之間的怨氣值如下面左圖所示,右圖所示為罪犯的分配方法,市長看到的衝突事件影響力是3512(由2 號和3 號罪犯引發)。其他任何分法都不會比這個分法更優。
【資料範圍】 對於 30% 的資料有 N≤15。 對於 70% 的資料有 N≤2000,M≤50000。 對於 100% 的資料有 N≤20000,M≤100000。
解析:
帶權並查集和擴充套件域並查集均可。
說下擴充套件域並查集的做法,把每個人拆成兩個點分別表示與這個人一個監獄的集合和與這個人不同監獄的集合即可。
程式碼:
#include <bits/stdc++.h>
using namespace std;
const int Max=40005;
int n,m;
int father[Max];
struct shu{int x,y,w;};
shu a[100005];
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') f=-1,c-getchar();
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline bool comp(const shu &a,const shu &b){return a.w > b.w;}
inline int get(int v){return father[v]==v ? v : father[v]=get(father[v]);}
int main()
{
n=get_int(),m=get_int();
for(int i=1;i<=m;i++) a[i].x=get_int(),a[i].y=get_int(),a[i].w=get_int();
sort(a+1,a+m+1,comp);
for(int i=1;i<=(n<<1);i++) father[i]=i;
for(int i=1;i<=m;i++)
{
int x1=a[i].x,x2=x1+n,y1=a[i].y,y2=y1+n;
if(get(x1)==get(y1)) {cout<<a[i].w;return 0;}
else
{
if(get(x1)!=get(y2)) father[get(x1)]=get(y2);
if(get(x2)!=get(y1)) father[get(x2)]=get(y1);
}
}
cout<<"0\n";
return 0;
}