• 拓扑排序


    定义:将有向图中的顶点以线性方式进行排序。即对于任何连接自顶点u到顶点v的有向边uv,在最后的排序结果中,顶点u总是在顶点v的前面。

    前提条件: 必须是有向无环图(可以不连通)

    偏序/全序关系:

    所谓偏序,就是图中没有环(自己出发不能回到自己)

    所谓全序,就是在偏序的基础之上,有向无环图中的任意一对顶点还需要有明确的关系(有唯一拓扑序)(反映在图中,就是单向连通的关系,注意不能双向连通,那就成环了)

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

    算法—:Kahn算法(可加第二关键字)

    该算法的实现十分直观,关键在于需要维护一个入度为0的顶点的集合:

    每次从该集合中取出(没有特殊的取出规则)一个顶点,将该顶点放入保存结果的List中。

    紧接着循环遍历由该顶点引出的所有边,从图中移除这条边,同时获取该边的另外一个顶点,如果该顶点的入度在减去本条边之后为0,那么也将这个顶点放到入度为0的集合中。然后继续从集合中取出一个顶点直到集合为空。

    当集合为空之后,检查图中是否还存在任何边,如果存在的话,说明图中至少存在一条环路。不存在的话则返回结果List,此List中的顺序就是对图进行拓扑排序的结果。

    /****************************************************************************************************
    
                                                    拓扑排序 
                                                    Kahn算法
                            
    
    ********************************************************************************************************/
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<vector>
    using namespace std;
    priority_queue<int>a;
    vector<int>v[505];
    int size[505],list[505],top=0;//size为每个点入度,list为结果数组 
    int main(){
        int n,m,x,y;
        while(scanf("%d%d",&n,&m)!=EOF){
            top=0;
            memset(size,0,sizeof(size));
            while(!a.empty())a.pop();
            for(int i=0;i<m;i++){
                scanf("%d%d",&x,&y);
                v[x].push_back(y);
                size[y]++;
            }
            for(int i=1;i<=n;i++){//将所有入度为0的顶点加入队列
                if(!size[i])a.push(-i);
            }
            while(!a.empty()){
                int u=-a.top();
                a.pop();
                list[top++]=u;
                for(int i=0;i<v[u].size();i++){//u的每个邻接点v
                    size[v[u][i]]--;//删除边(u, v);
                    if(!size[v[u][i]])a.push(-v[u][i]);//如果删除边后v入度为0,则将v加入队列
                }
                v[u].clear();
            }
            bool d=0;
            for(int i=1;i<=n;i++){//如果图中还有边存在则存在环
                if(!v[i].empty())v[i].clear(),d=1;
            }
            if(d)printf("wrong
    ");
            else{
                for(int i=0;i<top-1;i++){
                    printf("%d ",list[i]);
                }
                printf("%d",list[top-1]);
                printf("
    ");
            }
        }
        return 0;
    }

     二.基于bfs的拓扑排序(不可加第二关键字)

    对于每个节点进行一遍dfs,dfs到的节点都在当前节点前面,没有遍历到的都与当前节点无关

    http://acm.hdu.edu.cn/showproblem.php?pid=3342

    /****************************************************************************************************
    
                                                    拓扑排序 
                                                基于DFS的拓扑排序
                            
    
    ********************************************************************************************************/
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<vector>
    using namespace std;
    vector<int>g[505];
    int vis[505],list[505],top=0;//vis表示节点访问状态,list为结果数组 
    bool dfs(int u)  
    {  
        vis[u] = -1;//-1用来表示顶点u正在访问  
        for(int i = 0 ; i < g[u].size() ; i ++)  {  
            if(vis[g[u][i]] == -1)//表示这个点进入了两次,肯定出现了环  
                return false;  
            else if(vis[g[u][i]] == 0)  {  
                if(!dfs(g[u][i]))return false;  
            }  
        }  
        vis[u] = 1;
        list[top++] = u;//放到结果数组里,输出的时候记得倒序输出,(回溯的原因)  
        return true;  
    }  
    int main(){
        int n,m,x,y;
        while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){
            bool d=0;
            memset(vis,0,sizeof(vis));
            for(int i=0;i<n;i++)g[i].clear();
            top=0;
            for(int i=0;i<m;i++){
                scanf("%d%d",&x,&y);
                g[x].push_back(y);
            }
            for(int i=0;i<n;i++){
                if(!vis[i])if(!dfs(i))d=1;
            }
            if(d)printf("NO
    ");
            else printf("YES
    ");
        } 
        return 0;
    } 
  • 相关阅读:
    linux查看日志文件内容命令tail、cat、tac、head、echo
    改变自己的128种方法,教你变得更优秀!
    php 23种设计模式
    Swoole消息推送
    PHP 出现 502 解决方案
    【centos7】添加开机启动服务/脚本
    curl 参数配置详解
    i系列标准-互联网周刊
    MySQL 设计与开发规范2
    Cocos Creator webviw网页置顶增加返回键的方法
  • 原文地址:https://www.cnblogs.com/bennettz/p/6724963.html
Copyright © 2020-2023  润新知