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

1 篇文章 0 订阅
1 篇文章 0 订阅

题目描述

输入N个人(编号从0到N-1),M条信息。每条信息可能有三种情况,分别是"A > B","A = B","A < B",分别表示A的Rating高于B,等于B,小于B。问根据这些信息,能否确定排名(根据Rating大小排序,Rating相同时编号大的排名靠前)。
若能够确定出这个高手榜输出"OK"。否则判断出错的原因,到底是因为信息不完全(输出"UNCERTAIN"),还是因为这些信息中包含冲突(输出"CONFLICT")。
Ps:注意,如果信息中同时包含冲突且信息不完全,就输出"CONFLICT"。

问题分析

问题一看就是拓扑排序,唯一问题就是“=”的处理,因为题目并没有要求输出排名,仅是判断排名是否确定,这样的话,优先处理“=”,将“=”连接的A、B看成同一个人,用并查集并到一个树。
例如1>2,0=1,3>1,优先处理“0=1”,令fa[1]=0,就将1用0表示,把剩下条件变成了0>2,3>0,再进行拓扑排序。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;

const int MAXN  = 10010;
const int MAXM  = 20010;

int fa[MAXN];
int in[MAXN]; // 入度
char c[MAXM];
int x[MAXM],y[MAXM];

vector<int> v[MAXN]; 

int n,m,num;
void init() {
    for (int i=0;i<n;i++) {
        fa[i] = i;
        in[i] = 0;
        v[i].clear();
    }
    num = n; //num表示等效人数,A=B将AB看做一个人时,num--
}
int find(int x) {
    if (fa[x]==x) return fa[x];
    return fa[x] = find(fa[x]);
}
void bfs() {
    queue<int> q;
    int i;
    for (i=0;i<n;i++) {
        if (in[i]==0 && fa[i]==i) q.push(i);
    }
    bool flag = true;
    while (!q.empty()) {
        if  (q.size()>1) flag = false; //队列一次应该只加入一个人的,若队列容量>1,说明有多人同时入度为0,就是说这几个人无法比较大小,排名不确定。
        int now = q.front();
        q.pop();
        num--;
        for (i=0;i<v[now].size();i++) {
            int temp = v[now][i];
            in[temp]--;
            if (in[temp]==0) q.push(temp); //入度为0,则加入队列
        }
    }
    if (num>0) printf("CONFLICT\n"); //num>0,说明不是所有人入度为0,即存在环,比如a>b,b>a,in[a]=1,in[b]=1
    else if (flag) printf("OK\n");
    else printf("UNCERTAIN\n");
}
int main()
{
    while (scanf("%d %d",&n,&m)!=EOF) {
        init();
        for (int i=1;i<=m;i++) {
            scanf("%d %c %d",&x[i],&c[i],&y[i]);
            if (c[i]=='=') {  //优先处理“=”的情况 直接将两个点看做一个点来用 并用并查集来表示关系 
                int xx = find(x[i]);
                int yy = find(y[i]);
                if (xx!=yy) {
                    fa[yy] = xx;
                    num--;
                }
            }
        }
        for (int i=1;i<=m;i++) {
            if (c[i]!='=') {
                int xx = find(x[i]);
                int yy = find(y[i]);
                if (c[i]=='>') {
                    v[xx].push_back(yy);
                    in[yy]++;
                }
                else {
                    v[yy].push_back(xx);
                    in[xx]++;
                }
            }
        }
        bfs();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值