zoukankan      html  css  js  c++  java
  • hdu 1811 拓扑排序+并查集

    Problem Description 
    自从Lele开发了Rating系统,他的Tetris事业更是如虎添翼,不久他遍把这个游戏推向了全球。 

    为了更好的符合那些爱好者的喜好,Lele又想了一个新点子:他将制作一个全球Tetris高手排行榜,定时更新,名堂要比福布斯富豪榜还响。关于如何排名,这个不用说都知道是根据Rating从高到低来排,如果两个人具有相同的Rating,那就按这几个人的RP从高到低来排。 

    终于,Lele要开始行动了,对N个人进行排名。为了方便起见,每个人都已经被编号,分别从0到N-1,并且编号越大,RP就越高。 
    同时Lele从狗仔队里取得一些(M个)关于Rating的信息。这些信息可能有三种情况,分别是"A > B","A = B","A < B",分别表示A的Rating高于B,等于B,小于B。 

    现在Lele并不是让你来帮他制作这个高手榜,他只是想知道,根据这些信息是否能够确定出这个高手榜,是的话就输出"OK"。否则就请你判断出错的原因,到底是因为信息不完全(输出"UNCERTAIN"),还是因为这些信息中包含冲突(输出"CONFLICT")。 
    注意,如果信息中同时包含冲突且信息不完全,就输出"CONFLICT"。 

    Input 
    本题目包含多组测试,请处理到文件结束。 
    每组测试第一行包含两个整数N,M(0<=N<=10000,0<=M<=20000),分别表示要排名的人数以及得到的关系数。 
    接下来有M行,分别表示这些关系 

    Output 
    对于每组测试,在一行里按题目要求输出 

    Sample Input 
    3 3 
    0 > 1 
    1 < 2 
    0 > 2 
    4 4 
    1 = 2 
    1 > 3 
    2 > 0 
    0 > 1 
    3 3 
    1 > 0 
    1 > 2 
    2 < 1 

    Sample Output 
    OK 
    CONFLICT 
    UNCERTAIN
     

    思路:把=号用并查集处理以后(所有同一集合的数字用根数字来表示,以集合根节点为单位增加边)就是显而易见的拓扑排序了 
    所用知识: 
    *如果一次入队入度为零的点大于1则说明拓扑排序序列不唯一,用分叉树去理解的话,就是同一层有多个节点 
    *如果需要排序的总个数小于给定的个数,则说明存在回路

    #include <iostream>
    #include <fstream>
    #include <algorithm>
    #include <string>
    #include <set>
    //#include <map>
    #include <queue>
    #include <utility>
    #include <stack>
    #include <list>
    #include <vector>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <ctime>
    #include <ctype.h>
    using namespace std;
    
    int pre[10005], L[20005], R[20005], ind[10005], n;    //L:左值,R:右值
    char ch[20005];    //ch: 中值,ind: 入度
    
    struct node{
        int son;    //儿子的编号
        node *next;    //指向下一个儿子,即为son的兄弟
    }*N[10005];
    
    int find (int a)        //并查集:寻找终极父节点,即a所属的集合的根节点
    {
        while (a != pre[a])
            a = pre[a];
        return a;
    }
    
    void insert (int a, int b)    //b插入作为a的儿子,a这个链表表示a的所有儿子,不包括孙子
    {
        node *p = new node;
        p->son = b;
        p->next = N[a];
        N[a] = p;
    }
    
    void init ()    //初始化
    {
        int i;
        for (i = 0; i < n; i++)
        {
            pre[i] = i;
            ind[i] = 0;
            N[i] = NULL;
        }
    }
    
    int main()
    {
        int i, A, B, m, num;
        while (~scanf ("%d%d", &n, &m))
        {
            init ();
            num = n;    //num是需要排序的点的个数
            for (i = 0; i < m; i++)
            {
                scanf ("%d %c %d", L+i, ch+i, R+i);
                if (ch[i] == '=')    //=则合并为同一集合
                {
                    A = find (L[i]);
                    B = find (R[i]);
                    if (A != B)    //需要排序的个数-1,既然相等就不需要进行拓扑了,顺序已定
                        pre[B] = A, num--;
                }
            }
            bool flag = false;
            for (i = 0; i < m; i++)    //合并完之后才可以进行以下操作
            {
                if (ch[i] == '=')    //=的情况刚刚已经处理完
                    continue;
                A = find (L[i]);
                B = find (R[i]);
                if (A == B)
                {//两个值属于同一集合,也就是刚刚上面相等合并为同一集合,现在却不等了,矛盾!
                    flag = true;
                    break;    //矛盾就可以直接退出循环了
                }
                if (ch[i] == '>')
                {
                    insert (A, B);    //注意,必须用A,B(即集合的根节点)进行入边操作
                    ind[B]++;   //入度+1
                }
                else
                {
                    insert (B, A);    //同理
                    ind[A]++;
                }
            }
            if (flag)
            {
                puts ("CONFLICT");    //矛盾
                continue;
            }
            queue<int> q;
            for (i = 0; i < n; i++)
                if (ind[i] == 0 && i == find(i))
                    q.push (i);    //找到拓扑排序的终极父亲,入度为0,且为集合根节点
            while (!q.empty())
            {
                if (q.size() > 1)//(类似于分叉的树)同一层有多个点,则必有多个拓扑排序序列
                    flag = true;
                num--;   //排好一个点了
                int t = q.front();
                q.pop();
                for (node *i = N[t]; i; i = i->next)
                    if (--ind[i->son] == 0)//入度为1才可入队列,为了防止重复入队列,自减
                        q.push (i->son);
            }
            if (num > 0)    //根据题意,优先判断是否矛盾
                puts ("CONFLICT");
            else if (flag)    //有多个拓扑排序序列,所以不确定
                puts ("UNCERTAIN");
            else puts ("OK");
        }
        return 0;
    }


     

  • 相关阅读:
    用charles工具 mock数据(原创)
    css img图片和背景图片按容器大小自适应大小(居中裁切)
    js 实现图片上传
    Java基础之接口
    Java基础之字符串
    Java基础之常用API
    Java基础之面向对象
    Java基础之方法与流程控制
    Java基础之常量、变量、数据类型、运算符
    Java基础之JVM、JRE、JDK
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134236.html
Copyright © 2011-2022 走看看