欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【二分】【二分图染色】关押罪犯

程序员文章站 2024-03-17 15:30:40
...

Luogu P1525

题目:

将图中的点分成两部分,使得两部分中存在的边的最大值最小

题解:

分成两部分,额,第一反应应该就是二分图
带权怎么办?
我们考虑要求的是其中最大的最小,似乎是二分答案
于是,我们二分答案然后验证,要是边权>mid说明我们必须在二分图中给它连上,其他就可以不管,判一下是否是二分图,然后就AC啦qwq

#include<bits/stdc++.h>
using namespace std;
const int N=2e4+10,M=2e5+10;
int n,m;
int head[N],nex[M],to[M],val[M],tot;
void build(int u,int v,int w)
{
	tot++;nex[tot]=head[u];to[tot]=v;val[tot]=w;head[u]=tot;
}
int col[N],cnt,tim;
bool dfs(int u,int f)
{
	if(!col[u])col[u]=cnt;
	else {
		if(col[u]!=cnt)return 0;
		return 1;
	}
	bool tmp=1;
	for(int i=head[u];i;i=nex[i])
	{
		int v=to[i];if(v==f)continue;
		if(val[i]>tim)
		{
			cnt=col[u]^1;
			tmp&=dfs(v,u);
		}
	}return tmp;
}
bool check(int c)
{
	tim=c;
	for(int i=1;i<=n;i++)col[i]=0;
	for(int i=1;i<=n;i++)
	if(!col[i])
	{
		cnt=2;
		if(!dfs(i,i))return 0;
	}return 1;
}
int main()
{
	int ma=0;
	scanf("%d%d",&n,&m);
	for(int x,y,z,i=1;i<=m;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		build(x,y,z);build(y,x,z);
		ma=max(ma,z);
	}
	int l=0,r=ma,mid,ans;
	while(l<=r)
	{
		mid=(l+r)>>1; 
		if(check(mid))r=mid-1,ans=mid;
		else 		l=mid+1;
	}
	printf("%d",ans);
}