HDU 1811 Rank of Tetris

题意:
(中文)
思路:
把所有得分相同的选手放到同一个集合里面,然后对这些结合的关系进行拓扑排序,看是否可以存在一个完全的有向无环图。
1.利用并查集合并集合。
2.利用队列进行拓扑排序,如果队列里面的元素个数超过1个了,那么就说明此时信息缺失(因为这些队列里面的参赛选手都没有比它们大的了,他们之间的相互关系无法确定),如果最后入队的个数小于集合的个数,说明在图中有环,就是冲突了(因为环里面没有任何一个点的入度为0)
Code:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<stack>
#include<list>
#include<map>
#include<set>

#define TEST

#define LL long long
#define Mt(f, x) memset(f, x, sizeof(f));
#define rep(i, s, e) for(int i = (s); i <= (e); ++i)
#ifdef TEST
    #define See(a) cout << #a << " = " << a << endl;
    #define See2(a, b) cout << #a << " = " << a << ' ' << #b << " = " << b << endl;
    #define debug(a, s, e) rep(_i, s, e) {cout << a[_i] << ' ';} cout << endl;
    #define debug2(a, s, e, ss, ee) rep(i_, s, e) {debug(a[i_], ss, ee)}
#else
    #define See(a)
    #define See2(a, b)
    #define debug(a, s, e)
    #define debug2(a, s, e, ss, ee)
#endif // TEST

const int MAX = 2e9;
const int MIN = -2e9;
const double eps = 1e-8;
const double PI = acos(-1.0);

using namespace std;

const int N = 20000 + 5;

char op[N][2];
int a[N], b[N];
int uf[N], in[N];
vector<int> vec[N];

void init(int n)
{
    for(int i = 0; i < n; ++i)
    {
        uf[i] = i;
        vec[i].clear();
    }
    Mt(in, 0);
}

int fd(int n)
{
    if(uf[n] != n)
    {
        uf[n] = fd(uf[n]);
    }
    return uf[n];
}

void unionSet(int a, int b)
{
    int f1 = fd(a), f2 = fd(b);
    if(f1 != f2)
        uf[f1] = uf[f2];
}

int bfs(int n, int tem, bool &flag)
{
    queue<int> Q;
    for(int i = 0; i < n; ++i)
    {
        if(!in[i] && fd(i) == i)//选择所有入读为0的根(合法情况下只有一个)
        {
            Q.push(fd(i));
        }
    }
    while(!Q.empty())
    {
        if(Q.size() > 1) flag = true;
        int st = Q.front(); Q.pop();
        tem--;
        for(int i = 0; i < vec[st].size(); ++i)
        {
            const int &to = vec[st][i];
            if(--in[to] == 0)//把通过此点连接的所有入读都减一,并找到这里面入度为0的点
            {
                Q.push(to);
            }
        }
    }
    return tem;
}

int main()
{
    int n, m;
    while(~scanf("%d%d", &n, &m))
    {
        init(n);
        int num = n;//最开始假设结合个数为n
        for(int i = 0; i < m; ++i)
        {
            scanf("%d%s%d",  &a[i], op[i], &b[i]);
            if(op[i][0] == '=')
            {
                unionSet(a[i], b[i]);
                num--;//合并集合时,集合个数减1
            }
        }
        bool clash = false;
        for(int i = 0; i < m; ++i)
        {
            if(op[i][0] == '=') continue;
            int fa = fd(a[i]), fb = fd(b[i]);
            if(fa == fb)//找到各自的集合,看是否是同一个集合里面的
            {
                clash = true;
                break;
            }
            if(op[i][0] == '<')
            {
                vec[fa].push_back(fb);
                in[fb]++;
            }
            else
            {
                vec[fb].push_back(fa);
                in[fa]++;
            }
        }
        if(clash)
        {
            printf("CONFLICT\n");
            continue;
        }
        bool flag = false;
        int tem = bfs(n, num, flag);//拓扑排序 flag记录是否是信息不全,返回还没有入队的集合个数
        if(tem > 0)
        {
            printf("CONFLICT\n");
        }
        else if(flag)
        {
            printf("UNCERTAIN\n");
        }
        else
        {
            printf("OK\n");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值