D170 二分图判定 二分+染色法 P1525 [NOIP 2010 提高组] 关押罪犯

D170 二分图 染色法+二分 P1525 [NOIP 2010 提高组] 关押罪犯_哔哩哔哩_bilibili

 

P1525 [NOIP 2010 提高组] 关押罪犯 - 洛谷

n 名罪犯,两个监狱,需要把怨气值大的两人分到两个监狱,求最小化每个监狱内的最大怨气值

思路

将罪犯看做点,仇恨关系看做无向边,边权是怨气值

将所有点分成两组,使得各组内的边权最大值尽可能小

考虑对怨气值二分答案,在 $[0,10^9]$ 之间枚举边权 mid

判断能否将所有点分成两组,使得所有权值大于 mid 的边都在组间,而不在组内

也就是判断由所有点以及所有权值大于 mid 的边能否构成二分图

样例,当 mid=3512 时,大于 mid 的三条边权的端点都被分在两个组,mid 就是所求答案

二分图判定,当然是染色法啦

复习:D24【模板】二分图判定 染色法 - 董晓 - 博客园       

     C123【模板】扩展域并查集 P1892 [BOI2003] 团伙 - 董晓 - 博客园

 

// 二分图 二分+染色法 O((n+m)*30)
#include<bits/stdc++.h>
using namespace std;

const int N=20010;
vector<pair<int,int> > e[N]; //邻接表
int n,m,color[N];

bool dfs(int u,int c,int mid){
  color[u]=c;
  for(auto i:e[u]){
    int v=i.first, w=i.second;
    if(w<=mid) continue; //只保留[mid+1,1e9]的边权
    if(!color[v]){
      if(dfs(v,3-c,mid)) return 1; //有奇环,返1
    }
    else if(color[v]==c) return 1; //有奇环,返1
  }
  return 0; //无奇环,返0
}
bool check(int mid){
  memset(color,0,sizeof color);
  for(int i=1; i<=n; i++)
    if(!color[i])if(dfs(i,1,mid)) return 0; //有奇环,返0
  return 1; //无奇环,返1
}
int main(){
  scanf("%d%d",&n,&m);
  for(int a,b,c;m--;){
    scanf("%d%d%d",&a,&b,&c);
    e[a].push_back({b,c});
    e[b].push_back({a,c});
  }
  
  int l=-1,r=1e9+1;
  while(l+1<r){
    int mid=l+r>>1;
    if(check(mid)) r=mid; //无奇环,扩大可行区[r,1e9]
    else l=mid;
  }
  printf("%d\n",r);
}

 

posted @ 2026-05-26 16:51  董晓  阅读(25)  评论(0)    收藏  举报