zoukankan      html  css  js  c++  java
  • HDU1811 拓扑排序判环+并查集

    HDU Rank of Tetris

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1811

    题意:中文问题就不解释题意了。

    这道题其实就是一个拓扑排序判圈,我的博客里面其他几篇拓扑排序判圈的套路一样。但是这道题与他们不同的的是在大小关系里面存在一种 “=”的关系,这就意味的那些序号不同的点,实际上是一个点。共享入度和出度。我们可以通过并查集将他们合并,合成一个点。这里说一下如何判断信息不完全。我们早先在做拓扑排序,多种排列方式的时候,按照字典序输出。我们建立一个优先队列,维护字典序,这个时候堆里是有很多元素的,我们通过优先队列取出最小或者最大,实际上这些元素在拓扑排序中是等价关系,也就是说他们之间的大小关系无法比较。在这道题中,如果滞留在队列中的元素超过一个说明有两个元素无法比较的,就说明了答案是UNCLEARED。直接看代码吧!,具体细节写在注释里面了。

    //Author: xiaowuga
    #include <bits/stdc++.h>
    #define maxx INT_MAX
    #define minn INT_MIN
    #define inf 0x3f3f3f3f
    const long long N=10000+10;
    using namespace std;
    typedef long long LL;
    vector<int>p[N];
    int f[N];
    int in[N];
    struct node{
        int x,y;
        char ch;
    }oj[N];
     int n,m;
    int ct=0,flag=0;
    //并查集套路
    int Find(int x){
        return f[x]==x?x:f[x]=Find(f[x]);
    }
    void topo(){
        queue<int>q;
        while(!q.empty()) q.pop();
        for(int i=0;i<n;i++) if(!in[i]&&Find(i)==i) q.push(i);//首先得是并查集中的根,然后出度为0
        while(!q.empty()){
            if(q.size()>1) flag=1;//同级元素大于一个说明有至少有两个元素无法比较,所以信息不完全
            int t=q.front();q.pop();
            ct++;
            for(int i=0;i<p[t].size();i++){
                int tmp=p[t][i];
                if(--in[tmp]==0) q.push(tmp);
            }
        }
        if(ct!=n) cout<<"CONFLICT"<<endl;
        else if(flag) cout<<"UNCERTAIN"<<endl;
        else cout<<"OK"<<endl;
    }
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);
        while(cin>>n>>m){
            for(int i=0;i<n;i++) f[i]=i;
            memset(in,0,sizeof(in));
            for(int i=0;i<n;i++) p[i].clear();
            int x,y;
            ct=flag=0;
            //先处理'='带来的点的减少,建立并查集缩点
            for(int i=0;i<m;i++){
                cin>>oj[i].x>>oj[i].ch>>oj[i].y;
                if(oj[i].ch=='='){
                    x=Find(oj[i].x);
                    y=Find(oj[i].y);
                    if(x!=y) {f[x]=y;ct++;}//缩点了别忘了ct++,因为相当于总点数减少了一个
                }
            }
            //根据缩完点的点边关系,反向建图(正向建图也可以)
            for(int i=0;i<m;i++){
                if(oj[i].ch=='=') continue;
                x=Find(oj[i].x);
                y=Find(oj[i].y);
                if(oj[i].ch=='>'){
                    p[y].push_back(x);     
                    in[x]++;
                }
                else{
                    p[x].push_back(y);
                    in[y]++;
                }
                
            }
            //并查集处理完建图之后就是常规的拓扑排序
            topo();
        }
        return 0;
    }

    在最小生成树的克鲁斯卡尔算法里,并查集被用来判断是否形成环路,正如我在我的其他几份博文里面说的那样,我认为在一个图中,如果出现环,那么环可以缩成一个点。环上的点实际上是等价的,也就是说并查集实际上是通过边的关系,说明两个不同的点,合并成一个点,通过一个根共享他们的信息。a=b全等价于a>b,a<b这样两条边。我们根据这个信息把a,b合并。通过一个根可以是a,也可以是b来查询这个整体的信息。总结一句并查集就是把一些不同的东西合并在一起,一起查询的工具。

  • 相关阅读:
    zookeeper使用场景
    zookeeper安装配置
    hadoop 远程调试
    deep learning笔记
    Sentiment Analysis(1)-Dependency Tree-based Sentiment Classification using CRFs with Hidden Variables
    PRML阅读笔记 introduction
    Python 学习笔记(2)
    python nltk 学习笔记(5) Learning to Classify Text
    python nltk 学习笔记(4) Writing Structured Programs
    python nltk 学习笔记(3) processing raw text
  • 原文地址:https://www.cnblogs.com/xiaowuga/p/7220492.html
Copyright © 2011-2022 走看看