涉及知识点:
solution:
- 本题解法不唯一
- 首先先讲一下并查集+贪心的做法:
- 题意要求答案最小,所以仇恨值偏大的一对可以视为敌人分开,所以先根据仇恨值sort
- 根据敌人的敌人就是友人,假如我们将a和b分开,b和c分开,那a和c就相当于在同一个监狱里,b在另外一个监狱里
- 所以通过并查集,开大一倍数组,用来维护罪犯的补集,即不在同一个监狱的罪犯集合
- 下面讲一下二分 + 二分图(需要有二分图的前提知识):
- 很明显答案是要求最大值最小,所以二分答案
- 然后根据染色法判断二分图是否成立,以及边权的最大值是否小于等于当前的二分答案
并查集+贪心 std:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 200005;
int f[maxn];
struct node{
int u,v,w;
}a[maxn*10];
bool cmp(node p1,node p2){
return p1.w > p2.w;
}
int find(int x){
return f[x] == x ? f[x] : f[x] = find(f[x]);
}
void unite(int x,int y){
x = find(x),y = find(y);
if(x != y)
f[x] = y;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=2*n;i++)f[i] = i;
for(int i=1;i<=m;i++)cin>>a[i].u>>a[i].v>>a[i].w;
sort(a+1,a+1+m,cmp);
for(int i=1;i<=m;i++)
{
int x = a[i].u;
int y = a[i].v;
x = find(x),y = find(y);
if(x == y){
cout<<a[i].w<<endl;
return 0;
}
f[x] = find(n + a[i].v);
f[y] = find(n + a[i].u);
}
cout<<"0"<<endl;
return 0;
}
二分 + 二分图 std(感谢清楚姐的小迷弟贡献的代码):
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 20010, M = 200010;
int n, m;
int h[N], e[M], w[M], ne[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 u, int c, int mid)
{
color[u] = c;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (w[i] <= mid) continue;
if (color[j])
{
if (color[j] == c) return false;
}
else if (!dfs(j, 3 - c, mid)) return false;
}
return true;
}
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 false;
return true;
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
while (m -- )
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, c);
}
int l = 0, r = 1e9;
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
printf("%d
", r);
return 0;
}