洛谷P1525 關押罪犯 【思維 + 二分圖判定】
阿新 • • 發佈:2018-12-11
傳送門 題意: 給出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);
}