HDU1811并查集+拓扑排序

85 阅读2分钟

题目

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"

解题思路

偏序求全序,比较常见的有Floyd和拓扑排序,看数据范围显然是拓扑排序。根据><建有向边,进行拓扑排序,如果某一时刻队列中有两个元素,说明两个人的rank相同,也就是"UNCERTAIN"。

但是题目中加入了=,还需要判断"CONFLICT"。如果没有=,冲突的情况只有A>B && B>A,也就是成环的情况。有了=,多了一种冲突情况,也就是A=B && A>C && C>B
我们可以用并查集将两个元素合并成一个元素。这样就把等于的情况又转换成了上面成环的情况。A=B && A>C && C>B ===》 A=B=X && X>C && C>X

拓扑排序中,是否所有元素的rank确定就是判断是否成环的条件,

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 10010, M = 20010;
int n, m;
struct node
{
    int v, next;
} edge[M * 2];
int head[N], ct = 1;
int degree[N];
int vis[N];
int fa[N];

void add(int u, int v)
{
    edge[ct].v = v;
    edge[ct].next = head[u];
    head[u] = ct++;
    degree[v]++;
}

set<int> st;
int topo(int ned)
{
    queue<int> q;
    int ans1 = 0, ans2 = 0; //信息不全 、 冲突
    for (int i = 1; i <= n; i++)
    {
        if (degree[i] == 0 && st.count(i))
        {
            vis[i] = 1;
            q.push(i);
        }
    }
    if (q.size() >= 2)
        ans1 = 1;
    while (q.size())
    {
        int pos = q.front();
        q.pop();
        for (int i = head[pos]; i; i = edge[i].next)
        {
            int v = edge[i].v;
            degree[v]--;
            if (degree[v] == 0 && !vis[v] && st.count(v))
                q.push(v), vis[v] = 1;
        }
        if (q.size() >= 2)
            ans1 = 1;
    }
    int res = 0;
    for (int i = 1; i <= n; i++)
        if (vis[i])
            res++;
    if (res < ned)
        ans2 = 1;
    if (ans2)
        return 2;
    else if (ans1)
        return 0;
    return 1;
}

int a[20010], b[20010];
char c[20010];

int find(int x)
{
    if (x == fa[x])
        return x;
    return fa[x] = find(fa[x]);
}
void mix(int a, int b)
{
    int ffa = find(a);
    int ffb = find(b);
    fa[ffa] = ffb;
}
void solve()
{
    st.clear();
    ct = 1;
    for (int i = 1; i <= n; i++)
        head[i] = degree[i] = vis[i] = 0, fa[i] = i;

    for (int i = 1; i <= m; i++)
    {
        scanf("%d %c %d", &a[i], &c[i], &b[i]);
        ++a[i], ++b[i];
        if (c[i] == '=')
            mix(a[i], b[i]);
    }
    for (int i = 1; i <= n; i++)
    {
        int ii = find(i);
        st.insert(ii);
    }

    for (int i = 1; i <= m; i++)
    {
        a[i] = find(a[i]), b[i] = find(b[i]);
        if (c[i] == '=')
            continue;
        if (c[i] == '<')
            swap(a[i], b[i]);
        add(a[i], b[i]);
    }
    int opt = topo(st.size());

    if (opt == 1)
        puts("OK");
    else if (opt == 2)
        puts("CONFLICT");
    else if (opt == 0)
        puts("UNCERTAIN");
}
int main()
{
    while (cin >> n >> m)
        solve();
    return 0;
}