拓扑排序 hdu1811 Rank of Tetris

这题有3个方面值得深思

1.=的处理,读入的时候就先考虑=的,用并查集合并,把第二个节点完全用第一个节点代替,后面建图的时候都使用的是并查集的根节点即可

2.判断是否是唯一确定的,就看队列中的size是否永远<=1,若出现>=2,则说明同时有两个点的入度为0,就不能唯一确定

3.判断是否有冲突,先记录并查集后,有多少个连通块,记为sum,然后再判断队列中一共运行了多少个点,记为cnt,若cnt等于sum,那么就没冲突,否则就有冲突,因为如果存在环,那么必然那整个环上的任意一点的入度都会大于0,所以,这个环的节点永远不会进入队列


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<iostream>
#include<functional>
#include<algorithm>

using namespace std;
typedef long long LL;

const int mod=142857;
const int MX=10000+5;
const int INF=0x3f3f3f3f;

int rear=0;
int vis[MX],IN[MX],P[MX];
vector<int>G[MX];

int find(int x){
    return P[x]==x?x:(P[x]=find(P[x]));
}

void Union(int u,int v){
    int p1=find(u),p2=find(v);
    P[p1]=p2;
}

struct Edge{
    int u,v;
}E[2*MX];

int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        rear=0;
        memset(IN,0,sizeof(IN));
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++){
            G[i].clear();
            P[i]=i;
        }

        for(int i=1;i<=m;i++){
            int u,v;char op[10];
            scanf("%d%s%d",&u,op,&v);
            if(op[0]=='<'){
                E[++rear].u=u;
                E[rear].v=v;
            }else if(op[0]=='>'){
                E[++rear].u=v;
                E[rear].v=u;
            }else Union(u,v);
        }

        int sign=0;
        for(int i=1;i<=rear;i++){
            int p1=find(E[i].u),p2=find(E[i].v);
            G[p1].push_back(p2);
            IN[p2]++;
        }

        int cnt=0,sum=0;
        for(int i=0;i<n;i++) vis[find(i)]=1;
        for(int i=0;i<n;i++) sum+=vis[i];

        queue<int>work;
        for(int i=0;i<n;i++){
            if(vis[i]&&!IN[i]){
               work.push(i);
            }
        }

        while(!work.empty()){
            if(work.size()>=2) sign=2;
            int u=work.front();
            work.pop();

            cnt++;
            for(int i=0;i<G[u].size();i++){
                int v=G[u][i];
                IN[v]--;
                if(!IN[v]) work.push(v);
            }
        }

        if(cnt!=sum) sign=1;

        printf("%s\n",sign==0?"OK":(sign==1?"CONFLICT":"UNCERTAIN"));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值