HDU1811 Rank of Tetris(并查集+拓扑排序)

题目链接

自从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
对于每组测试,在一行里按题目要求输出

1.题目大意:给出n个序号并给出一些大于等于小于关系,让我们判断能否排成一个拓扑序列。注意冲突和不完全

2.一开始做看到大小关系,觉得是拓扑排序,但是相等关系并不知道要怎么判断。后来才知道,是并查集!但是如果并查集的话拓扑排序怎么处理那几个相等的关系,又陷入了疑惑

3.原来这题思路如此巧妙:因为并查集不就是设置了一个father数组并且路径压缩嘛,那么每个序号都是一个集合,我们拓扑排序的时候都拿father数组里的值当做已知节点!但是问题又来了,输入时是混乱的输入,前面比较时不能判断后面出现的“=”关系,怎么办?先保存下来条件啊!我感觉自己有点笨,这么简单的办法都想不出来,那么我们就先处理给出条件的所有"="关系,接着处理所有大于小于,也就是处理每个给出节点的father节点,记录入度。在处理大于小于关系时记录是否出现父节点相等,如果出现直接就是冲突。接着拓扑排序,在拓扑排序时只找出所有的祖宗节点,因为所有相等的都连接在祖先节点上,那么就是father[i]==i的节点,并记录个数,接下来队列处理时记录处理多少节点。最后如果这两者不等就是冲突。但是我们还要一个res,如果有入队超过一个节点的,即当前队列超过一个节点那就证明不能得到唯一的拓扑序列,也就是条件不足。最后都判断后那么就是OK

代码:

#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
#include <map>
using namespace std;
const int maxn=1e4+10;
const int maxm=2e4+10;
int father[maxn],in[maxn];
int a[maxm],b[maxm];
char c[maxm];
vector<int> G[maxn];
queue<int> q;
int tot,cnt,res;

int Find(int x){
    return x==father[x]?x:father[x]=Find(father[x]);
}

void bfs_topsort(int n){
    for(int i=0;i<n;i++){
        int fi=Find(i);  //貌似直接写father[i]就行了
        if(fi==i){
            cnt++;
            if(in[fi]==0) q.push(fi);
        }
    }
    while(!q.empty()){
        if(q.size()>1) res=1;  //队列存的节点必须是唯一的才能排成唯一拓扑序列
        int u=q.front();
        q.pop(),tot++;
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            in[v]--;
            if(in[v]==0) q.push(v);
        }
    }
}

void init(int n){
    tot=cnt=res=0;
    for(int i=0;i<n;i++) father[i]=i;
    for(int i=0;i<n;i++) G[i].clear();
    memset(in,0,sizeof in);
}

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        int flag=1;
        init(n);
        for(int i=1;i<=m;i++){  //第一次输入只处理"="
            scanf("%d %c %d",&a[i],&c[i],&b[i]);
            if(c[i]=='='){
                int fa=Find(a[i]);
                int fb=Find(b[i]);
                if(fa!=fb) father[fb]=fa;
            }
        }
        for(int i=1;i<=m;i++){   //记录了输入,再处理">,<"
            if(c[i]=='>'){
                int fa=Find(a[i]);
                int fb=Find(b[i]);
                if(fa==fb){ flag=0;break; }   //是否同时出现等于和大于小于的关系
                G[fa].push_back(fb);
                in[fb]++;

            }else if(c[i]=='<'){
                int fa=Find(a[i]);
                int fb=Find(b[i]);
                if(fa==fb){ flag=0;break; }   //是否同时出现等于和大于小于的关系
                G[fb].push_back(fa);
                in[fa]++;

            }
        }
        if(!flag){ printf("CONFLICT\n");continue; }
        bfs_topsort(n);
        if(cnt!=tot)
            printf("CONFLICT\n");
        else{
            if(res) printf("UNCERTAIN\n");
            else printf("OK\n");
        }

    }
    return 0;
}
发布了128 篇原创文章 · 获赞 7 · 访问量 5253

猜你喜欢

转载自blog.csdn.net/qq_44691917/article/details/104705678