传送门

一道比较简单的并查集题,我们先把所有冲突事件按照影响力排序,之后从大到小处理他们。每次对于两个敌人,如果其中一个人没有敌人,那么就把他的敌人设为当前这个人,否则把他的敌人所在的集合与这个人合并即可。判断的时候如果两人在同一集合即不合法。

此题还有一种做法。我们要求的是最大值最小,所以我们还是很容易想到二分答案,之后我们就把问题转化成了判定性问题。怎么判定呢?因为如果要是满足条件的话,每对罪犯必然属于两个不同的监狱,也就是属于两个集合,他们其实构成了一个二分图。我们只要二分当前的值x,之后在跑图的时候,把图中所有小于x的边去掉,然后我们用常用的二分图判定染色法即可。

不过这个题我每次二分的好像有点问题……答案总是比标准情况多1,所以我选择了减1,不过要特判答案是0的情况。而且二分图的还比并查集稍微慢那么一点……

并查集代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
using namespace std;
typedef long long ll;
const int M = 100005;
const int N = 10000005;
 
int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
    if(ch == '-') op = -1;
    ch = getchar();
    }
    while(ch >='0' && ch <= '9')
    {
    ans *= 10;
    ans += ch - '0';
    ch = getchar();
    }
    return ans * op;
}

struct fight
{
    int x,y,z;
    bool operator < (const fight &g) const
    {
        return z > g.z;
    }
}f[M];

int n,m,fa[M],e[M];

int getfa(int x)
{ 
    return (x == fa[x]) ? x : fa[x] = getfa(fa[x]);
}

void merge(int x,int y)
{
    int r1 = getfa(x),r2 = getfa(y);
    fa[r2] = r1;
}

bool pd(int x,int y)
{
    int r1 = getfa(x),r2 = getfa(y);
    return (r1 == r2) ? 1 : 0;
}

int main()
{
    n = read(),m = read();
    rep(i,1,n) fa[i] = i;
    rep(i,1,m) f[i].x = read(),f[i].y = read(),f[i].z = read();
    sort(f+1,f+1+m);
    rep(i,1,m+1)
    {
    if(pd(f[i].x,f[i].y)) printf("%d\n",f[i].z),exit(0);
    if(!e[f[i].x]) e[f[i].x] = f[i].y;
    else merge(e[f[i].x],f[i].y);
    if(!e[f[i].y]) e[f[i].y] = f[i].x;
    else merge(e[f[i].y],f[i].x);
    }
    return 0;
}
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-09-21
  • 2021-12-21
  • 2021-06-25
  • 2022-03-01
猜你喜欢
  • 2021-12-30
  • 2021-06-24
  • 2021-09-10
  • 2021-11-02
相关资源
相似解决方案