codevs1069 關押罪犯 [並查集]

1069 關押罪犯 2010年NOIP全國聯賽提高組
時間限制: 1 s
空間限制: 128000 KB
題目等級 : 鑽石 Diamond
題解
查看運行結果
題目描述 Description
S 城現有兩座監獄,一共關押着N 名罪犯,編號分別爲1~N。他們之間的關係自然也極
不和諧。很多罪犯之間甚至積怨已久,如果客觀條件具備則隨時可能爆發衝突。我們用“怨氣值”(一個正整數值)來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之間的積怨越多。如果兩名怨氣值爲c 的罪犯被關押在同一監獄,他們倆之間會發生摩擦,並造成影響力爲c 的衝突事件。

每年年末,警察局會將本年內監獄中的所有衝突事件按影響力從大到小排成一個列表,然後上報到S 城Z 市長那裏。公務繁忙的Z 市長只會去看列表中的第一個事件的影響力,如果影響很壞,他就會考慮撤換警察局長。

在詳細考察了N 名罪犯間的矛盾關係後,警察局長覺得壓力巨大。他準備將罪犯們在兩座監獄內重新分配,以求產生的衝突事件影響力都較小,從而保住自己的烏紗帽。假設只要處於同一監獄內的某兩個罪犯間有仇恨,那麼他們一定會在每年的某個時候發生摩擦。那麼,應如何分配罪犯,才能使Z 市長看到的那個衝突事件的影響力最小?這個最小值是少?

輸入描述 Input Description
第一行爲兩個正整數N 和M,分別表示罪犯的數目以及存在仇恨的罪犯對數。

接下來的M 行每行爲三個正整數aj,bj,cj,表示aj 號和bj 號罪犯之間存在仇恨,其怨氣值爲cj。數據保證,且每對罪犯組合只出現一次。

輸出描述 Output Description
共1 行,爲Z 市長看到的那個衝突事件的影響力。如果本年內監獄

中未發生任何衝突事件,請輸出0。

樣例輸入 Sample Input
4 6

1 4 2534

2 3 3512

1 2 28351

1 3 6618

2 4 1805

3 4 12884

樣例輸出 Sample Output
3512

數據範圍及提示 Data Size & Hint
罪犯之間的怨氣值如下面左圖所示,右圖所示爲罪犯的分配方法,市長看到的衝突事件

影響力是3512(由2 號和3 號罪犯引發)。其他任何分法都不會比這個分法更優。

【數據範圍】

對於30%的數據有N≤ 15。

對於70%的數據有N≤ 2000,M≤ 50000。

對於100%的數據有N≤ 20000,M≤ 100000。

題意:把點分配到兩個點集使得兩個點集中最大邊的值最小。
分析:考慮我們面對樣例時,只能貪心判斷某些點不能在一起,但並不能確定兩個點集具體有哪些點,於是這裏要用到虛點的思想。
具體實現:對邊的權值進行排序由大到小處理,先滿足小的,每沒枚舉到一條邊,若兩實點在一起(即已經必須在一個點集裏),或兩虛點在一起(即有一個集合兩個點都容不下)就直接輸出該點值因爲該點不可能被滿足,否則,就把一點的虛點和另一點實點所在集合相連,該點實點與另一點虛點集合相連,來表示這兩點無法處在一個點集裏。
注意特殊情況的處理:都能滿足,輸出0;

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=2e4+5;
struct node
{
    int fin,sta,wor;
}roa[maxn*5];
int fa[maxn*2],n,m;
bool cmp(node x,node y)
{
    return x.wor>y.wor;
}
int lookfor(int u)
{
    return fa[u]=(fa[u]==u?u:lookfor(fa[u]));
}
void unio(int u,int v)
{
    int fu=lookfor(u),fv=lookfor(v);
    fa[fu]=fv;
}
void prin(int u)
{
    printf("%d",roa[u].wor);
    exit(0);
}
void work()
{
    for(int i=1;i<=m;i++){
        if(lookfor(roa[i].sta+n)==lookfor(fa[roa[i].fin+n]))
            prin(i);
        if(lookfor(roa[i].sta)==lookfor(roa[i].fin))
            prin(i);
        unio(roa[i].sta,roa[i].fin+n);
        unio(roa[i].fin,roa[i].sta+n);
    }
    printf("0");
}
void init()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=2*n;i++)fa[i]=i;
    for(int i=1;i<=m;i++)
        scanf("%d %d %d",&roa[i].fin,&roa[i].sta,&roa[i].wor);
    sort(roa+1,roa+m+1,cmp);
}
int main()
{
    freopen("codevs1069.in","r",stdin);
    freopen("codevs1069.out","w",stdout);
    init();
    work();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章