257. 关押罪犯

题目链接

257. 关押罪犯

S 城现有两座监狱,一共关押着 N 名罪犯,编号分别为 1N

他们之间的关系自然也极不和谐。

很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。

我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。

如果两名怨气值为 c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为 c 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到 SZ 市长那里。

公务繁忙的 Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。

在详细考察了 N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。

他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。

假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。

那么,应如何分配罪犯,才能使 Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?

输入格式

第一行为两个正整数 NM,分别表示罪犯的数目以及存在仇恨的罪犯对数。

接下来的 M 行每行为三个正整数 ajbjcj,表示 aj 号和 bj 号罪犯之间存在仇恨,其怨气值为 cj

数据保证 1aj<bj<N,0<cj109 且每对罪犯组合只出现一次。

输出格式

输出共 1 行,为 Z 市长看到的那个冲突事件的影响力。

如果本年内监狱中未发生任何冲突事件,请输出 0

数据范围

N20000,M100000

输入样例:

4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884

输出样例:

3512

解题思路

染色法判定二分图,二分

对于同一个监狱来说,增加一个犯人,只可能增加边权的最大值,即本题答案具有单调性,不妨考虑二分答案 x,对于小于等于 x 的边的两个端点,显然无论这两个点放在二分图的哪一个集合都不会影响答案,故只需要那些大于 x 的边的两个端点,即这两个端点不可能放在同一个集合中,即问这些点形成的图是否为二分图,染色法判定即可

  • 时间复杂度:O((n+m)×logw)

贪心,扩展域并查集

贪心策略:向将所有的边权按从大到小排序,两边的端点尽量不放在一个集合里面,直到矛盾出现该权值即答案

证明:要使所有满足要求的边权的最大值最小,即两个集合内部的边权要尽量小,由于从大到小排序,一开始的边权对应的两个端点应该放在两个不同的集合,否则后面所有构成的答案都要小于等当前权值,即当前权值就是答案,故需要维护两个点属于不同类,可用扩展域并查集实现

  • 时间复杂度:O(mlogm)

代码

  • 二分
// Problem: 关押罪犯
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/259/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=20005,M=200005;
int n,m;
int h[N],ne[M],w[M],e[M],idx;
int color[N];
void add(int a,int b,int c)
{
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool dfs(int x,int c,int limit)
{
	color[x]=c;
	for(int i=h[x];~i;i=ne[i])
	{
		if(w[i]<=limit)continue;
		int y=e[i];
		if(!color[y])
		{
			if(!dfs(y,3-c,limit))return false;
		}
		else if(color[y]==c)return false;
	}
	return true;
}
bool ck(int x)
{
	for(int i=1;i<=n;i++)color[i]=0;
	for(int i=1;i<=n;i++)
		if(!color[i])
			if(!dfs(i,1,x))return false;
	return true;
}
int main()
{
	memset(h,-1,sizeof h);
    scanf("%d%d",&n,&m);
    int l=0,r=0;
    for(int i=1;i<=m;i++)
    {
    	int x,y,z;
    	scanf("%d%d%d",&x,&y,&z);
    	add(x,y,z),add(y,x,z);
    	r=max(r,z);
    }
    while(l<r)
    {
    	int mid=l+r>>1;
    	if(ck(mid))r=mid;
    	else
    		l=mid+1;
    }
    printf("%d",l);
    return 0;
}
  • 贪心
// Problem: 关押罪犯
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/259/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=40005,M=100005;
int n,m;
int fa[N];
struct A
{
	int x,y,z;
	bool operator<(const A &o)const
	{
		return z>o.z;
	}
}a[M];
int find(int x)
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=2*n;i++)fa[i]=i;
	for(int i=1;i<=m;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
	sort(a+1,a+1+m);
	for(int i=1;i<=m;i++)
	{
		int x=a[i].x,y=a[i].y;
		if(find(x)==find(y))
		{
			printf("%d",a[i].z);
			return 0;
		}
		fa[find(x)]=find(y+n),fa[find(x+n)]=find(y);
	}
	puts("0");
    return 0;
}

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16935537.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示