zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    算法题汇集
    C# WinForm MDI左右分栏 多文档
    DDoS和CC攻击的区别
    搭建java程序写的博客Jpress
    U盘图标DIY方法
    磁盘空间不够用?教你一键清理电脑重复文件Duplicate File Finder
    给WordPress文章页URL赋予.html后缀
    使用七牛云和PicGo搭建图床
    wordpress好用的Markdown插件WP Editor.MD
    虚拟主机、VPS、云服务器三者的区别
  • 原文地址:https://www.cnblogs.com/captain1/p/9834440.html
Copyright © 2011-2022 走看看