NOIP2010 关押罪犯

传送门

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

此题还有一种做法。我们要求的是最大值最小,所以我们还是很容易想到二分答案,之后我们就把问题转化成了判定性问题。怎么判定呢?因为如果要是满足条件的话,每对罪犯必然属于两个不同的监狱,也就是属于两个集合,他们其实构成了一个二分图。我们只要二分当前的值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('
')
#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
",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

二分图代码:

#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('
')
#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 edge
{
    int next,to,v;
}e[M<<1];

int n,m,x,y,z,maxx,ecnt,head[M],L,R,ans,col[M];

void add(int x,int y,int z)
{
    e[++ecnt].to = y;
    e[ecnt].next = head[x];
    e[ecnt].v = z;
    head[x] = ecnt;
}

bool pd(int x)
{
    memset(col,0,sizeof(col));
    queue <int> q;
    while(!q.empty()) q.pop();
    rep(j,1,n)
    {
    if(col[j]) continue;
    q.push(j),col[j] = 1;
    while(!q.empty())
    {
        int k = q.front();q.pop();
        for(int i = head[k];i;i = e[i].next)
        {
        int t = e[i].to;
        if(e[i].v < x) continue;
        if(!col[t])
        {
            col[t] = (col[k] == 1) ? 2 : 1;
            q.push(t);
        }
        else if(col[t] == col[k]) return 0;
        }
    }
    }
    return 1;
}

int main()
{
    n = read(),m = read();
    rep(i,1,m) x = read(),y = read(),z = read(),add(x,y,z),add(y,x,z),maxx = max(maxx,z);
    L = 0,R = maxx+1;
    while(L <= R)
    {
    int mid = (L+R) >> 1;
    //printf("#%d
",mid);
    if(pd(mid)) ans = mid,R = mid-1;
    else L = mid + 1;
    }
    if(!ans) printf("0
");
    else printf("%d
",ans - 1);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/captain1/p/9834440.html