天天看點

wikioi-天梯-提高一等-并查集-1069:關押罪犯

題目描述 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。

類型:圖論  難度:2

題意:有一些罪犯,給出一些兩個罪犯之間的怨氣值,現在要求把這些罪犯分到兩個監獄中,且每個監獄的怨氣值取在其中的罪犯的最大怨氣值,問怎麼配置設定罪犯,使兩個監獄的最大怨氣值最小。

分析:并查集題目,一開始想的有點繞,因為給出兩個罪犯的怨氣值,則兩個罪犯最好不在一個監獄中,即給出的是不等價的關系,故解題步驟如下:

1、先将給出的資料按怨氣值從大到小排序

2、從大到小周遊資料,用opp[i]代表和罪犯i相斥的罪犯,分情況讨論,設目前資料的罪犯為a,b,怨氣值為c:

(1)若a,b均無相斥罪犯,置opp[a]=b,opp[b]=a,将彼此作為相斥罪犯

(2)若a有相斥b沒有,那麼opp[a]和b就在同一所監獄,合并opp[a]和b為一個等價類,并且,置opp[b]=a

(3)若b有相斥a沒有,情況類似(2)

(4)若a,b都有相斥,那麼看a,b是否在一個等價類中,如果在,那麼目前的c就是最大的怨氣值,傳回c(因為是按從大到小周遊);若不在一個等價類,那麼a和opp[b],b和opp[a]在一個等價類,合并,然後置opp[b]=a,opp[a]=b。

(5)繼續周遊下一組資料

代碼:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;

int n,m,p;
int fa[20010],path[100010][3],opp[20010];

int mfind(int a)
{
    if(fa[a] != a) fa[a] = mfind(fa[a]);
    return fa[a];
}

void mmerge(int a,int b)
{
    fa[mfind(a)] = mfind(b);
}

int cmp(const void*a, const void*b)
{
    return ((int*)b)[2]-((int*)a)[2];
}

int fun(int x)
{
    if(x>=m) return 0;
    int a = path[x][0];
    int b = path[x][1];
    int c = path[x][2];
    int faa = mfind(a);
    int fab = mfind(b);
    int opa = opp[a];
    int opb = opp[b];

    int ans = 0;
    if(!opa && !opb)
    {
        opp[a] = b;
        opp[b] = a;
    }
    else if(opa && !opb)
    {
        mmerge(opa,b);
        opp[b] = a;
    }
    else if(!opa && opb)
    {
        mmerge(a,opb);
        opp[a] = b;
    }
    else
    {
        if(faa == fab)
        {
            return c;
        }
        else
        {
            mmerge(a,opb);
            mmerge(b,opa);
        }
    }
    return fun(x+1);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++)
        fa[i] = i;
    int a,b;
    for(int i=0; i<m; i++)
    {
        for(int j=0; j<3; j++)
            scanf("%d",&path[i][j]);
    }
    qsort(path,m,sizeof(int)*3,cmp);
    
    memset(opp,0,sizeof(opp));
    printf("%d\n",fun(0));
}