更好的閱讀體驗ios
Portal1: Luogugit
Portal2: LibreOJgithub
\(S\)城現有兩座監獄,一共關押着\(N\)名罪犯,編號分別爲\(1 - N\)。他們之間的關係天然也極不和諧。不少罪犯之間甚至積怨已久,若是客觀條件具有則隨時可能爆發衝突。咱們用「怨氣值」(一個正整數值)來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之間的積怨越多。若是兩名怨氣值爲\(c\) 的罪犯被關押在同一監獄,他們倆之間會發生摩擦,並形成影響力爲\(c\)的衝突事件。測試
每一年年底,警察局會將本年內監獄中的全部衝突事件按影響力從大到小排成一個列表,而後上報到S 城Z 市長那裏。公務繁忙的Z 市長只會去看列表中的第一個事件的影響力,若是影響很壞,他就會考慮撤換警察局長。spa
在詳細考察了\(N\)名罪犯間的矛盾關係後,警察局長以爲壓力巨大。他準備將罪犯們在兩座監獄內從新分配,以求產生的衝突事件影響力都較小,從而保住本身的烏紗帽。假設只要處於同一監獄內的某兩個罪犯間有仇恨,那麼他們必定會在每一年的某個時候發生摩擦。code
那麼,應如何分配罪犯,才能使\(\rm Z\)市長看到的那個衝突事件的影響力最小?這個最小值是多少?blog
每行中兩個數之間用一個空格隔開。第一行爲兩個正整數\(N, M\),分別表示罪犯的數目以及存在仇恨的罪犯對數。接下來的\(M\)行每行爲三個正整數\(a_j, b_j, c_j\),表示\(a_j\)號和\(b_j\)號罪犯之間存在仇恨,其怨氣值爲\(c_j\)。數據保證\(1<aj \le b_j \le N ,0 < cj \le 1, 000, 000, 000\),且每對罪犯組合只出現一次。事件
共\(1\) 行,爲\(\rm Z\)市長看到的那個衝突事件的影響力。若是本年內監獄中未發生任何衝突事件,請輸出\(0\)。ip
4 6 1 4 2534 2 3 3512 1 2 28351 1 3 6618 2 4 1805 3 4 12884
3512
【輸入輸出樣例說明】罪犯之間的怨氣值以下面左圖所示,右圖所示爲罪犯的分配方法,市長看到的衝突事件影響力是\(3512\)(由\(2\)號和\(3\)號罪犯引起)。其餘任何分法都不會比這個分法更優。get
【數據範圍】
對於\(30\%\)的數據有\(N \le 15\)。
對於\(70\%\)的數據有\(N \le 2000,M \le 50000\)。
對於\(100\%\)的數據有\(N \le 20000,M \le 100000\)。
題目要把罪犯們放到兩個監獄,很容易想到是二分圖。
咱們能夠先用二分答案,對於每一條大於二分出來的邊(也就是不能放在一個監獄的兩個罪犯,放入了答案就大於二分的值了)構成的圖,判斷是否能構成二分圖,也就是是否能夠將這些點分到兩個區域。若是能夠,那麼說明了這個最大破壞度是可行的,因此就擴大二分值,最後求出最大值的最小值。
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> #include<queue> using namespace std; const int MAXN = 100005, MAXM = 200005; struct EDGE { int nxt, to, val; } edge[MAXM]; int n, m, u, v, val, cnt, U[MAXN], V[MAXN], VAL[MAXN], col[MAXM], head[MAXM]; inline void addedge(int u, int v, int val) {//鄰接表存圖 edge[++cnt].to = v; edge[cnt].val = val; edge[cnt].nxt = head[u]; head[u] = cnt; } inline bool check(int x) {//黑白染色,判斷二分圖 queue<int> Q; memset(col, 0, sizeof(col)); for (int i = 1; i <= n; i++) if (!col[i]) { Q.push(i); col[i] = 1; while (!Q.empty()) { int u = Q.front(); Q.pop(); for (int i = head[u]; ~i; i = edge[i].nxt) { int v = edge[i].to; if (edge[i].val >= x) { if (!col[v]) { col[v] = 3 - col[u];//標記狀態(顏色) Q.push(v); } else if (col[u] == col[v]) return 0;//若是衝突,就返回不是 } } } } return 1; } int main() { scanf("%d%d", &n, &m); int r = -1; memset(head, -1, sizeof(head)); for (int i = 1; i <= m; i++) { scanf("%d%d%d", &u, &v, &val); r = max(r, val); addedge(u, v, val); addedge(v, u, val);//雙向邊 } r++; int l = 0; while (l + 1 < r) {//二分答案 int mid = l + r >> 1; if (check(mid)) r = mid; else l = mid; } printf("%d\n", l); return 0; }