洛谷 關押罪犯 NOIP2010提高組複賽

2022-05-13 04:03:42 字數 3383 閱讀 6125

s 城現有兩座監獄,一共關押著n 名罪犯,編號分別為1~n。他們之間的關係自然也極不和諧。很多罪犯之間甚至積怨已久,如果客觀條件具備則隨時可能爆發衝突。我們用「怨氣值」(乙個正整數值)來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之間的積怨越多。如果兩名怨氣值為c 的罪犯被關押在同一監獄,他們倆之間會發生摩擦,並造成影響力為c 的衝突事件。

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

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

那麼,應如何分配罪犯,才能使z 市長看到的那個衝突事件的影響力最小?這個最小值是多少?

輸入格式:

輸入檔案的每行中兩個數之間用乙個空格隔開。第一行為兩個正整數n 和m,分別表示罪犯的數目以及存在仇恨的罪犯對數。接下來的m 行每行為三個正整數aj,bj,cj,表示aj 號和bj 號罪犯之間存在仇恨,其怨氣值為cj。資料保證1輸出格式:

共1 行,為z 市長看到的那個衝突事件的影響力。如果本年內監獄中未發生任何衝突事件,請輸出0。

輸入樣例#1:

4 6

1 4 2534

2 3 3512

1 2 28351

1 3 6618

2 4 1805

3 4 12884

輸出樣例#1:

3512
【輸入輸出樣例說明】罪犯之間的怨氣值如下面左圖所示,右圖所示為罪犯的分配方法,市長看到的衝突事件影響力是3512(由2 號和3 號罪犯引發)。其他任何分法都不會比這個分法更優。

【資料範圍】對於30%的資料有n≤ 15。對於70%的資料有n≤ 2000,m≤ 50000。對於100%的資料有n≤ 20000,m≤ 100000。

思路1:

考慮用二分答案+二分圖判斷

我們不難想到,a與b有c這麼多的矛盾,則可以說a與b間有權重為c的邊,這樣就構成了有n個頂點m條邊的無向圖。

將罪犯分配到兩個監獄中,不難想到是二分圖。

排序罪犯的怒氣值c,進行二分查詢,對於當前找到的這個怒氣值(邊)mid,我們將圖中比這條mid邊權重小或等於的邊暫時刪去,判斷剩下的圖能否構成乙個二分圖,如果構成則當前的這個怒氣值mid即為所求,輸出結束程式即可,不要忘了如果沒有任何衝突事件發生則輸出0.

拓展:二分圖判斷——染色法

從其中乙個頂點開始,將跟它鄰接的點染成與其不同的顏色,如果鄰接的點有相同顏色的,則說明不是二分圖,每次用bfs遍歷即可

判斷**如下(源自:

1 #include 2 #include 3 #include 4

using

namespace

std;56

const

int n=510;7

intcolor[n],graph[n][n];89

//0為白色,1為黑色

10bool bfs(int s, int

n)11

26if(graph[from][i]&&color[from]==color[i]) return

false;//

顏色有相同,則不是二分圖27}

28}29return

true;30

}3132int

main()

3342

bool flag=false;43

for(i=1;i<=n;i++)

44if(color[i]==-1&&!bfs(i,n)) //

遍歷各個連通分支

45

49if

(flag)

50 cout<

<

51else

52 cout<

yes"

<

53return0;

54 }

思路2:

考慮用並查集+貪心思想

這個方法較上面的方法容易理解,貪心地:我們希望怒氣值很大的兩個罪犯不在同乙個監獄,如遇到兩個罪犯不得不在乙個監獄時,這時候輸出的結果即為最大值。

我們按照並查集路徑優化的思想,兩個監獄各選出乙個頭子,這樣我們在判斷兩個罪犯是否要放在兩個監獄時,只有看看他們之前是否就歸附於同乙個頭子,如果之前兩人都歸附於同乙個監獄的頭子,輸出就ok,否則安排他倆進兩個監獄。

按照怒氣值從大到小依次取出兩個罪犯,看看他們能否放在兩個監獄:

如果能放,必須要滿足不歸附於同乙個頭子。

如果不能放,則安排他倆進進不同監獄,然後兩個罪犯分別當上兩個監獄的頭子(即讓原來的監獄頭子歸附於當前a與b)。

1 #include 2 #include 3 #include 4 #include 5 #include 6

using

namespace

std;

7 typedef struct conflict//

儲存矛盾資訊

8conflict;

1112

int against[20002]=;//

against[i]儲存i的敵人

13int father[20002];//

記錄這個節點的父親

14 conflict infermation[100002];//

記錄資訊陣列

1516

bool cmp(conflict x,conflict y)//

排序函式

1720

21int find(int x)//

尋找x節點的頭子(並查集+路徑壓縮)

2226

27int

main()

2839 sort(infermation+1,infermation+m+1,cmp);//

按矛盾值從大到小排序結構體

40for(i=1;i<=n;i++)

4144

for(i=1;i<=m;i++)//

從大到小取出矛盾值判斷 45

51if(!against[infermation[i].a])//

如果a沒有敵人

5255

else

5659

if(!against[infermation[i].b])//

如果b沒有敵人

60

63else

64 67}

68 printf("

0\n");//

沒有衝突找到則輸出0

69return0;

70 }

noip2010 關押罪犯

s 城現有兩座監獄,一共關押著n 名罪犯,編號分別為1 n。他們之間的關係自然也極 不和諧。很多罪犯之間甚至積怨已久,如果客觀條件具備則隨時可能爆發衝突。我們用 怨 氣值 乙個正整數值 來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之 間的積怨越多。如果兩名怨氣值為c 的罪犯被關押在同一監...

NOIP2010關押罪犯

s 城現有兩座監獄,一共關押著n 名罪犯,編號分別為1 n。他們之間的關係自然也極不和諧。很多罪犯之間甚至積怨已久,如果客觀條件具備則隨時可能爆發衝突。我們用 怨氣值 乙個正整數值 來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之間的積怨越多。如果兩名怨氣值為c 的罪犯被關押在同一監獄,他...

NOIP 2010 關押罪犯

題目描述 s 城現有兩座監獄,一共關押著n 名罪犯,編號分別為1 n。他們之間的關係自然也極不和諧。很多罪犯之間甚至積怨已久,如果客觀條件具備則隨時可能爆發衝突。我們用 怨氣值 乙個正整數值 來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之間的積怨越多。如果兩名怨氣值為c 的罪犯被關押在同...