1. 程式人生 > 其它 >257. 關押罪犯

257. 關押罪犯

題目連結

257. 關押罪犯

\(S\) 城現有兩座監獄,一共關押著 \(N\) 名罪犯,編號分別為 \(1 \sim N\)

他們之間的關係自然也極不和諧。

很多罪犯之間甚至積怨已久,如果客觀條件具備則隨時可能爆發衝突。

我們用“怨氣值”(一個正整數值)來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之間的積怨越多。

如果兩名怨氣值為 \(c\) 的罪犯被關押在同一監獄,他們倆之間會發生摩擦,並造成影響力為 \(c\) 的衝突事件。

每年年末,警察局會將本年內監獄中的所有衝突事件按影響力從大到小排成一個列表,然後上報到 \(S\)\(Z\) 市長那裡。

公務繁忙的 \(Z\)

市長只會去看列表中的第一個事件的影響力,如果影響很壞,他就會考慮撤換警察局長。

在詳細考察了 \(N\) 名罪犯間的矛盾關係後,警察局長覺得壓力巨大。

他準備將罪犯們在兩座監獄內重新分配,以求產生的衝突事件影響力都較小,從而保住自己的烏紗帽。

假設只要處於同一監獄內的某兩個罪犯間有仇恨,那麼他們一定會在每年的某個時候發生摩擦。

那麼,應如何分配罪犯,才能使 \(Z\) 市長看到的那個衝突事件的影響力最小?這個最小值是多少?

輸入格式

第一行為兩個正整數 \(N\)\(M\),分別表示罪犯的數目以及存在仇恨的罪犯對數。

接下來的 \(M\) 行每行為三個正整數 \(a_j,b_j,c_j\)

,表示 \(a_j\) 號和 \(b_j\) 號罪犯之間存在仇恨,其怨氣值為 \(c_j\)

資料保證 \(1 \le a_j < b_j < N,0 < c_j \le 10^9\) 且每對罪犯組合只出現一次。

輸出格式

輸出共 \(1\) 行,為 \(Z\) 市長看到的那個衝突事件的影響力。

如果本年內監獄中未發生任何衝突事件,請輸出 \(0\)

資料範圍

\(N \le 20000, M \le 100000\)

輸入樣例:

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)\times 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;
}