Link: P1525 NOIP2010 提高組 關押罪犯 - 洛谷
分析
首先題目給出了罪犯與罪犯之間的矛盾關係,這讓我們可以想到圖或並查集。然後,題目又說了要把罪犯分入兩個監獄,也就是把罪犯看作點,要把這些點分入兩個集合,這很自然地可以想到二分圖。再然後,市長只會去看列表中的第一個事件的影響力,而我們希望這個影響力最大的事件影響最小,所以又可以想到用二分來尋找答案。
到這個地步,做這道題的要素已經集齊,我們繼續分析具體怎麼做。首先我們透過二分來列舉最大影響力,然後考慮如何判斷是否合法。既然我們希望會造成大影響的罪犯儘量被分在兩個監獄裡,那麼我們可以在透過染色判定二分圖的時候加一個條件,即只有邊權大於等於當前列舉的最大影響力時,我們才考慮將兩個罪犯放在不同監獄裡面(學過二分圖應該看得懂這句話)。在這個限制下,如果染色完二分圖合法,那麼我們就接著嘗試檢測更小的答案;否則,說明當前答案過小,導致影響力大於等於當前答案的所有罪犯不能被正確地分入兩個監獄,接下來要嘗試更大檢測更大的答案。
注意二分答案的寫法,比較奇特 反正我沒見過,是我練得還太少了。
程式碼
#include <bits/stdc++.h>
using namespace std;
const int maxn = 20005;
const int maxm = 100005;
int n, m;
int head[maxn];
struct Edge {
int to, next, weight;
} edge[maxm << 1];
inline void insertEdge(int u, int v, int w) {
static int edgecnt;
edge[++edgecnt].to = v;
edge[edgecnt].weight = w;
edge[edgecnt].next = head[u];
head[u] = edgecnt;
}
int color[maxn];
bool dfs(int u, int col, int anger) {
color[u] = col;
for (int i = head[u]; i; i = edge[i].next) {
int v = edge[i].to, w = edge[i].weight;
if (w < anger) continue;
if (!color[v]) {
if (!dfs(v, 3 - col, anger)) return false;
} else if (color[u] == color[v]) return false;
}
return true;
}
inline bool check(int anger) {
memset(color, 0, sizeof(color));
for (int i = 1; i <= n; i++) {
if (!color[i]) {
if (!dfs(i, 1, anger)) return false;
}
}
return true;
}
int main() {
scanf("%d%d", &n, &m);
int l = 0, r = 0;
for (int i = 1; i <= m; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
insertEdge(u, v, w);
insertEdge(v, u, w);
r = max(r, w);
}
while (l + 1 < r) {
int mid = (l + r) >> 1;
if (check(mid)) r = mid;
else l = mid;
}
printf("%d", l);
return 0;
}