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

题意:给出一系列排名的信息,问你是否能确定排名,还是信息有冲突,或者信息不足。

这种确定先后顺序的题目我们很自然就能想到拓扑排序,拓扑排序时就可以判出是否冲突或信息不足,冲突就是有回路,信息不足就是在确定某个是谁时有多种选择,也就是在拓扑排序时入度为0的有多个。

代码如下,代码写的比较没有条理,因为之前拓扑排序用到时dfs版的,但后面想到这道题要有唯一的拓扑序列,所以应该用入度版。转换为入度后,问题变得容易了很多。所以以后写题时还是要先考虑清楚再敲代码。

#include <iostream>
#include <string>
#include <algorithm>
#include <list>
using namespace std;
const int MAXN = 10000;
const int MAXE = 20000;
const int NIL = -1;
const int INF = 0x3f3f3f3f;

struct Edge {
    int to, next;
} edge[MAXE];

struct Data {
    int u, v;
} dat[MAXE];
int parent[MAXN];
bool flag;
int cnt, head[MAXN];
int indegree[MAXN];
enum Color
{
    WHITE, GRAY, BLACK
} color[MAXN];
int find_parent(int x)
{
    return x == parent[x] ? x : parent[x] = find_parent(parent[x]);
}

inline void Union(int a, int b)    //a小b大
{
    int pa = find_parent(a);
    int pb = find_parent(b);
    if (pa != pb)
        parent[pa] = pb;
}

inline void init(int n)
{
    cnt = 0;
    for (int i = 0; i < n; ++i)
        parent[i] = i, head[i] = edge[i].next = NIL, color[i] = WHITE, indegree[i] = 0;
}

inline void add(int u, int v)
{
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}


int vertex[MAXN];
int vertex_num;

int main(void)
{
    int M, N;
    int u, v;
    char temp[10];
    while (scanf("%d %d", &N, &M) != EOF)
    {

        if (N == 0)
        {
            puts("OK");
            continue;
        }
        if (M == 0 && N == 1)
        {
            puts("OK");
            continue;
        }
        if (M == 0)
        {
            puts("UNCERTAIN");
            continue;
        }
        init(N);
        int id = 0;
        while (M--)
        {
            scanf("%d %s %d", &u, temp, &v);
            if (temp[0] == '=')
            {
                Union(min(u, v), max(u, v));
                continue;
            }
            if (temp[0] == '<')
                swap(u, v);
            dat[id].u = u;
            dat[id++].v = v;

        }
        flag = false;
        for (int i = 0; i < id; ++i)
        {
            u = dat[i].u;
            v = dat[i].v;
            //u->parent[v]
            int pu = find_parent(u);
            int pv = find_parent(v);
            if (pu == pv)
            {
                flag = true;    //CONFLICT
                break;
            }
            add(pu, pv);
            ++indegree[pv];
        }
        if (flag)
        {
            puts("CONFLICT");
            continue;
        }
        vertex_num = 0;
        for (int i = 0; i < N; ++i)
            if (parent[i] == i)
                vertex[vertex_num++] = i;
        bool flag2 = false;
        for (int i = 0; i < vertex_num; ++i)    //如果一次一个,那么n次就行
        {
            //找一个入度为零的点
            int v = NIL;
            int num = 0;
            for (int j = 0; j < vertex_num; ++j)
            {
                u = vertex[j];
                if (color[u] == WHITE && indegree[u] == 0)
                {
                    ++num;
                    v = u;
                }
            }
            if (v == NIL)
            {
                flag = true;
                break;
            }
            if (num > 1)
                flag2 = true;
            color[v] = BLACK;
            for (int i = head[v]; i != NIL; i = edge[i].next)
            {
                u = edge[i].to;
                if (color[u] == WHITE)
                    --indegree[u];
            }
        }
        if (flag)
            puts("CONFLICT");
        else if (flag2)
            puts("UNCERTAIN");
        else
            puts("OK");
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值