洛谷P1525 關押罪犯(二分+二分圖染色)
P1525 關押罪犯
問題描述 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<=1000000000,且每對罪犯組合只出現一次。
輸出格式 輸出檔案共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。
分析:求最小的最大值,顯然二分,對於一個mid,我們把所有大於mid的邊連起來,判斷是否構成二分圖即可。
程式碼
#include <cstdio> #include <algorithm> #include <queue> #define N 200005 using namespace std; struct arr { int x, y, w; }a[N],b[N]; int n,m,l,ls[N]; int color[N]; int cmp(arr p, arr q){return p.w<q.w;} void add(int x, int y, int w) { b[++l].y = y; b[l].x = ls[x]; b[l].w = w; ls[x] = l; } bool bfs(int x) { queue<int> q; while (!q.empty()) q.pop(); for (int i = 1; i <= n; i++) color[i] = 0; for (int i = 1; i <= n; i++) if (!color[i]) { color[i] = 1; q.push(i); while (q.size()) { int u = q.front(); q.pop(); for (int j = ls[u]; j; j = b[j].x) if (b[j].w > a[x].w) { if (!color[b[j].y]) color[b[j].y] = -color[u], q.push(b[j].y); else if (color[b[j].y] == color[u]) return false; } } } return true; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].w); add(a[i].x, a[i].y, a[i].w); add(a[i].y, a[i].x, a[i].w); } sort(a + 1, a + m + 1, cmp); int l = 0, r = m, pos = 0; while (l <= r) { int mid = (l + r) / 2; if (bfs(mid)) pos = mid, r = mid - 1; else l = mid + 1; } printf("%d", a[pos].w); }