1. 程式人生 > >洛谷P1525 關押罪犯 【思維 + 二分圖判定】

洛谷P1525 關押罪犯 【思維 + 二分圖判定】

傳送門 題意: 給出m對憎恨關係, 有一個憎恨值, 現在要將這n個人分成兩堆人, 要求這兩堆人中存在的憎恨值最大的最小, 問這個值是多少.

思路: 這種問題首先是二分, 然後我們如何check這個答案, 我們將所有邊的憎恨值大於我們這個答案的新建一幅圖, 然後我們判斷能否避免掉這幅圖的每一個邊的關係, 怎麼做了才能避免了? 實際上就是有憎恨關係的兩個人一定要放在不同的集合中, 然後怎麼判斷不能放在同一個集合中了? 實際上就是判斷一下當前這幅圖是不是二分圖就行了. 所以就是二分答案 + 判斷是否是二分圖

AC Code

const int maxn = 2e4 + 5;
const int maxm =
1e5 + 5; struct node { int to, next; }e[2*maxm]; struct edge { int u, v, w; }s[maxm]; int cnt, head[maxn]; void add(int u, int v) { e[cnt] = node{v, head[u]}; head[u] = cnt++; } int color[maxn]; bool flag; void dfs(int u, int fa, int col) { if (!flag) return ; if (!color[u])
color[u] = col; else if (color[u] != col) { flag = false; return ; } else return; for (int i = head[u] ; ~i ; i = e[i].next) { int to = e[i].to; if (to == fa) continue; dfs(to, u, 3-col); } } int n, m; bool ok(int x) { cnt = 0; Fill(head,
-1); for (int i = 1 ; i <= m ; i ++) { if (s[i].w > x) { add(s[i].u, s[i].v); add(s[i].v, s[i].u); } } flag = true; Fill(color, 0); for (int i = 1 ; i <= n ; i ++) { if (!color[i]) dfs(i, -1, 1); } return flag; } void solve() { scanf("%d%d", &n, &m); for (int i = 1 ; i <= m ; i ++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); s[i].u = u; s[i].v = v; s[i].w = w; } int l = 0, r = 1e9 +1, mid, ans; while(r >= l) { mid = (r + l) >> 1; if (ok(mid)) { ans = mid; r = mid - 1; } else l = mid + 1; } printf("%d\n", ans); }