牛客算法竞赛入门课第四节习题 关押罪犯
关押罪犯
https://ac.nowcoder.com/acm/problem/16591
题目描述
S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c 的冲突事件。每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。
在详细考察了 N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。那么,应如何分配罪犯,才能使 Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?
输入描述:
第一行为两个正整数N和M,分别表示罪犯的数目以及存在仇恨的罪犯对数。 接下来的M行每行为三个正整数aj,bj,cj,表示aj号和bj号罪犯之间存在仇恨,其怨气值为cj。 数据保证1≤aj<bj≤N,0<cj≤1,000,000,000,且每对罪犯组合只出现一次。输出描述:
共1行,为Z市长看到的那个冲突事件的影响力。如果本年内监狱中未发生任何冲突事件,请输出0。解析
题目的意思应该很容易就能看懂,就是有怨气的罪犯之间会发生冲突,然后发生冲突就会造成影响,所以就尽可能的不要将有怨气的的罪犯放在一起,一共有两个监狱很容易就能想到,优先把怨气高的的分开来,因此我们可以先将所有的怨气值排一个序,然后优先将怨气值大的分开来,
接下来就是如何实现了,利用并查集,将敌人的敌人分在一起(敌人的敌人就是朋友嘛),然后当第一次出现了两个的冲突不可避免的时候,那么他的影响值就是最大的了
剩下的看代码的注释就好了
code
#include<bits/stdc++.h> using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) typedef long long ll; typedef unsigned long long ull; typedef long double ld; const ll MOD = 1e9 + 7; inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar()) s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; } inline void write(ll x) { if (!x) { putchar('0'); return; } char F[40]; ll tmp = x > 0 ? x : -x; if (x < 0)putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0)putchar(F[--cnt]); } inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; } ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; } ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; } inline int lowbit(int x) { return x & (-x); } const int N = 20005; const int INF = 0x3f3f3f3f; int n , m ; int fa[N]; int b[N]; // 表示i的敌人是谁 struct node{ int u , v; //有冲突的两个犯罪 ll w; //影响值 }a[1000005]; //常规并查集操作 int find(int x){ return (fa[x] == x ? x : fa[x] = find(fa[x])); } void merge(int x , int y ){ fa[find(x)] = find(y); } //将影响值大的排在qian bool cmp(node a , node b){ return (a.w > b.w); } void solve(){ for(int i = 1 ; i <= m ; ++i){ if(find(a[i].u) == find(a[i].v)){ //当出现的第一个冲突不可避免 cout<<a[i].w<<endl; return ; } if(!b[a[i].u]){ //把u的敌人v 和u在b数组中的存的敌人 建立 朋友关系 b[a[i].u] = a[i].v; } else merge(a[i].v , b[a[i].u]); if(!b[a[i].v]){ // 把v的敌人u 和v在b数组中的存的敌人 建立 朋友关系 b[a[i].v] = a[i].u; } else merge(a[i].u , b[a[i].v]); } cout<<"0"<<endl; return ; } int main(void){ scanf("%d%d" , &n , &m); for(int i = 1 ; i <= m ; ++i){ scanf("%d%d%lld" , &a[i].u , &a[i].v , &a[i].w); } for(int i = 1 ; i <= n ; ++i){ fa[i] = i; } sort(a + 1 , a + m + 1 , cmp); solve(); return 0; }