并查集+拓扑 hdu 1811 Rank of Tetris

hdu 1811 Rank of Tetris
//hdu 1811 Rank of Tetris
//并查集+拓扑

//思路:用并查集把相等的点归到一起,再用拓扑

//纠结这题纠结了一整天,看了n多的博客感觉这个不错
//http://972169909-qq-com.iteye.com/blog/1052820


#include <stdio.h>
#include <string.h>
#include <queue>

using namespace std;

#define comein freopen("in.txt", "r", stdin);
#define N 10005
#define M 20005
#define INF 1<<30
#define eps 1e-5

struct edge
{
    int win, lost, next;
}adja[M];

int  tot;   //记录插入邻接表的个数
int degree[N];
int win[M], lost[M], head[N], set[N];

int find(int root)
{
    if(root == set[root])
        return root;
    return set[root] = find(set[root]);
}

void add_edge(int r_a, int r_b)
{
    degree[r_b]++;
    adja[++tot].win = r_a;
    adja[tot].lost = r_b;
    adja[tot].next = head[r_a];
    head[r_a] = tot;
}

void topo(int n_node, int all)
{
    queue<int>que;
    bool uncer = false;
    for(int i = 0; i < n_node; ++i)//要集合根节点且度为0的才可入队,若只判断
        if(degree[i] == 0 && i == find(i))  //degree[find(i)]==0,可能会重复入队
            que.push(i);
    while(!que.empty())
    {
        if(que.size() > 1)
            uncer = true;
        int now = que.front();
        que.pop();
        all--;
        for(int i = head[now]; i != -1; i = adja[i].next)
        {
            if(--degree[ adja[i].lost ] == 0)
                que.push( adja[i].lost );
        }
    }
    if(all > 0) //剩下的集合数大于1,则存在环
        puts("CONFLICT");
    else if(uncer == true)
        puts("UNCERTAIN");
    else
        puts("OK");
}

int main()
{
    // comein
    int n_node, n_pair;
    while(scanf("%d%d", &n_node, &n_pair) == 2)
    {
        for(int i = 0; i <= n_node; ++i)    //初始化并查集
            set[i] = i;

        int cnt = 0, all = n_node;    //若相等的点看做一个点,cnt记录总的点数

        for(int i = 0; i < n_pair; ++i)
        {
            int wn, lt;
            char ra;
            scanf("%d %c %d", &wn, &ra, &lt);
            if(ra == '=')
            {   //这里要先求出来r_a和r_b,然后下面要用set[r_a] = r_b
                //或set[r_b] = r_a,也不知道为什么,一天下来都在找bug
                //无缘无故就被de掉了,提交了30几次,有的这里不用这样也可以ac
                //有的不能,快崩溃了
                int r_a = find(wn), r_b = find(lt);
                if(r_a != r_b)
                {
                    set[r_a] = r_b;
                    all--;
                }
            }
            else if(ra == '>')
            {
                win[++cnt] = wn;
                lost[cnt] = lt;
            }
            else
            {
                win[++cnt] = lt;
                lost[cnt] = wn;
            }
        }

        memset(adja, 0, (n_pair+5)*sizeof(edge));
        for(int i = 0; i < n_node; ++i)
        {
            head[i] = -1;
            degree[i] = 0;
        }
        tot = 0;
        bool flag = false;
        for(int i = 1; i <= cnt; ++i)
        {
            int r_a = find(win[i]), r_b = find(lost[i]);
            if(r_a == r_b)  //上面的已经把'='的情况合并起来了
            {           //这里都是处理不等的,如果出现相等的,说明冲突了
                flag = true;
                break;
            }
            add_edge(r_a, r_b);
        }
        if(flag == true)
        {
            puts("CONFLICT");
            continue;
        }
        topo(n_node, all);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/gabo/p/2609228.html