HDU 1811 Rank of Tetris -- 并查集+拓扑排序

Rank of Tetris

Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7126 Accepted Submission(s): 2016

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

下面的AC代码,百度网上人家的代码,加上自己的理解和注释,重新敲了遍。
觉得就是刚开始没转过来 。用并查集 处理掉等于的情况,剩下就是个简单的拓扑处理。

/*
HDU 1811 Rank of Tetris
http://acm.hdu.edu.cn/showproblem.php?pid=1811
*/
#include <stdio.h>  
#include <iostream>  
#include <queue>  
#include <string.h>  
using namespace std;  

int n,m,sum; 
vector<int> G[10001]; // 邻接表 G[i][j1] G[i][j2] 表示 i > j1 , i > j2
int in_degree[10001]; // 入度
int f[10001]; // 并查集f[]数组
int find(int x)   // 并查集find
{  
    if(f[x]!=x)  
        f[x]=find(f[x]);  
    return f[x];  
}  
int judge(int a,int b) //用并查集判断是否已经相等,/ 没相等需要合并,同时计数的sum减1;  
{  
    int aa = find(a);  
    int bb = find(b);  
    if(aa == bb)  
        return 0;  
    f[aa] = bb; // 合并  
        return 1;  
}  

void add(int x,int y)      //邻接表添加 x > y ,x y是find处理后的结果  
{  
    if(find(G[x].begin(), G[x].end(), y) == G[x].end()) // 添加的是不重复的
    { 
        G[x].push_back(y);
        in_degree[y] ++ ; // y入度加1
    }
}  

void tuopu()    //拓扑排序  
{  
    int i ,j ;
    int t = 0;
    queue<int> q; // 存储入度为0的点  
    int flag = 0;
    for(i = 0 ; i < n; i ++) 
    {
        if(in_degree[i] == 0 && find(i) == i)  
        {  
            q.push(i);  
            t++;       //记录入度为0的点的个数
        } 
    }
    while( !q.empty() )
    {
        if(t > 1) // 至少两个元素 入度为0 他们的关系不确定
            flag = 1 ;
        int u = q.front();
        q.pop();
        t--;
        sum -- ;
        int len = G[u].size();
        for(i = 0; i < len ;i ++)
        {
            in_degree[ G[u][i] ] -- ; // G[i][j] i出去后 j的入读要减去1 然后再判断
            if(in_degree[ G[u][i] ] == 0)
            {
                q.push(G[u][i]);
                t ++;
            }
        }
    }
    if(sum > 0)  //sum > 0 说明出现了环  这个先判断 在判断关系是否明确 最后ok
        cout << "CONFLICT" << endl;  
    else if(flag == 1)  
        cout << "UNCERTAIN" <<endl;  
    else  
        cout<<"OK"<<endl; 
}  

int main()  
{  
    //freopen("in.txt","r",stdin);
    while(cin >> n >> m)  
    {  
        int i , j , k ;
        int x[20001] , y[20001];   // x c y 存储输入的内容
        char ch[20001] ;  
        sum = n ; // sum 初始为节点的总个数 并查集处理的时候需要减
        for(i = 0 ; i <= n ; i ++)   // 并查集f初始化
        {
            f[i] = i;  
            G[i].clear(); //清空
            in_degree[i] = 0 ; // 入度初始为0
        }
        // 输入 和 等于号用并查集处理
        for(i = 0 ; i < m ; i ++)  
        {  
            cin >> x[i] >> ch[i] >> y[i] ; 
            if(ch[i] == '=')  
                if(judge(x[i] , y[i]))  
                    sum --; // 个数减去1  
        }  
        //  大于,小于号 处理
        for(i = 0 ; i < m ; i ++)  
        {  
            if(ch[i] == '=')  
                continue;  
            int aa = find(x[i]);  
            int bb = find(y[i]);  
            if(ch[i] == '>') // 用>处理   
                add(aa,bb);   
            else  
                add(bb,aa);  
        }  
        tuopu();  // 拓扑处理 打印结果 
    }  
    return 0;  
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值