CH4901关押罪犯(二分答案+二分图判定)
题目大意
有n个罪犯,其中有m对憎恨关系,表示a和b的怨气值为c。
把这n个罪犯放到两个监狱中,使每个监狱里中最大的两罪犯的怒气值最小。
输出这个最大的怒气值。
解题思路
因为是使最大值最小,符合单调性,所以我们很容易想到二分答案。
所以问题就是判断最大怒气值是mid时是否能够将n个罪犯评分到两个监狱并且没有超过mid的罪犯。
我们把两个监狱看成两个集合,那么每个集合中没有超过mid的边,只有不同集合的点会有连边。
那么我们在两个怒气值超过mid的人之间连条边,问题就成了二分图判定。
用dfs染色判断是否有奇环,如果没有奇环就是二分图。
代码如下:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #define rep(x, l, r) for(int x = l; x <= r; x++) #define repd(x, r, l) for(int x = r; x >= l; x--) #define clr(x, y) memset(x, y, sizeof(x)) #define all(x) x.begin(), x.end() #define pb push_back #define mp make_pair #define MAXN 20005 #define MAXM 200005 #define fi first #define se second #define SZ(x) ((int)x.size()) using namespace std; typedef long long LL; typedef vector<int> vi; typedef pair<int, int> pii; const int INF = 0x3f3f3f3f; const int p = 10000007; int lowbit(int x){ return x & -x; } int fast_power(int a, int b){ int x; for(x = 1; b; b >>= 1){ if(b & 1) x = 1ll * x * a % p; a = 1ll * a * a % p; } return x; } int n, cnt, res; int head[MAXN], nxt[MAXM], to[MAXM], value[MAXM]; int col[MAXN]; void init(){ cnt = 0; clr(head, -1); } void add(int u, int v, int val){ nxt[cnt] = head[u]; head[u] = cnt; to[cnt] = v; value[cnt] = val; cnt++; } void dfs(int u, int s, int color){ if(res) return; col[u] = color; for(int e = head[u]; e != -1; e = nxt[e]){ int v = to[e], val = value[e]; if(val <= s) continue; if(!col[v]) dfs(v, s, 3 - color); else if(col[v] == color){ res = 1; return; } } } bool check(int mid){ clr(col, 0); rep(i, 1, n){ if(!col[i]){ res = 0; dfs(i, mid, 1); } if(res) return 0; } return 1; } int main(){ init(); int m; scanf("%d%d", &n, &m); int maxn = 0; rep(i, 1, m){ int u, v, val; scanf("%d%d%d", &u, &v, &val); maxn = max(maxn, val); add(u, v, val), add(v, u, val); } int l = 0, r = maxn, ans = 0; while(l <= r){ int mid = (l + r) >> 1; if(check(mid)){ ans = mid; r = mid - 1; } else l = mid + 1; } printf("%d\n", ans); return 0; }