zoukankan      html  css  js  c++  java
  • 图论三:拓扑排序

    一、基本知识

    1、定义:拓扑排序是对有向无圈图的排序,如果存在一条从vi--vj的路径,那么排序过程中vj必定在vi之后。

    2、排序条件:必须是有向图并且无圈;

    3、拓扑排序的结果不唯一。

    二、排序过程

    1、存储图结构:图的边集用邻接表存储,用vector数组来代替更好;还要一个存储入度的数组,表示每个节点的入度;

    一个队列在遍历图时存储图的每个节点(如果对序号有升序,降序需要可以用优先队列)。

    2、找到入度为0点,然后入队

    3、队列的头结点出队,遍历头结点的邻接节点,并且删除邻接点与头结点的边(就是入度-1)

    4、如果这个节点比入度变为0,则入队。

    5、重复2,3,4操作,直到队列为空,就是结束。

    三、例题

    (1)对结果序列有要求(字典序)

    题目链接:http://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=2153

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<string>
    #include<vector>
    using namespace std;
    const int maxn = 500;
    vector <int> edge[maxn];
    int in[maxn]={0},vis[maxn]={0},num=0;
    int main(void)
    {
        int i,j;
        char a,b,c; 
        string str,ans="";
        while(cin>>str)
        {
            a=str[0];b=str[1];c=str[2];
            if(vis[a]==0) vis[a]=1,num++;
            if(vis[c]==0) vis[c]=1,num++;
            if(b=='>') in[c]++,edge[a].push_back(c);
            else in[a]++,edge[c].push_back(a);
        }
        priority_queue <int,vector <int>, greater <int> > q;
        for(i=30;i<=220;i++)
        if(vis[i]&&in[i]==0) q.push(i);
        while(!q.empty())
        {
            int top=q.top();
            q.pop();
            ans+=(char)(top); 
            for(i=0;i<edge[top].size();i++)
            {
                in[edge[top][i]]--;
                if(in[edge[top][i]]==0) q.push(edge[top][i]);
            }
        }
        if(ans.size()!=num) cout<<"No Answer!"<<endl;
        else cout<<ans<<endl;
        return 0;
    }
    View Code

     

    (2)貌似字典序要求(比较坑)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4857

     思路:约束条件:“a必须在b之前”,“让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推。”,所依按照拓扑排序建立的图,最先出队的节点不能确定是否先输出,而最后的可以:

    eg:

    图为:

     3->6->5->1

    2->8->7->1

    4->9->10->1

    如果正序建图:2 8 7 3 6 5 4 9 10 1

    但正确结果是:3 6 5 2 8 7 4 9 10 1

    可以确定前面小的不一定在前面,但是后面大的一定在后面,所以可以逆序建图,然后逆序输出。

    参考文章:https://blog.csdn.net/qq_41713256/article/details/80805338

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<queue>
    using namespace std;
    const int maxn = 30030;
    int in[maxn],n,m;
    vector <int> edge[maxn],ans;
    int main(void)
    {
        int t,i,x,y;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            for(i=1;i<=n;i++) edge[i].clear(),in[i]=0;
            ans.clear();
            for(i=1;i<=m;i++)
            {
                scanf("%d%d",&x,&y);
                in[x]++;edge[y].push_back(x);
            }
            priority_queue <int> q;
            for(i=1;i<=n;i++) if(in[i]==0) q.push(i);
            while(!q.empty())
            {
                int top=q.top();
                ans.push_back(top);
                q.pop();
                for(i=0;i<edge[top].size();i++)
                {
                    in[edge[top][i]]--;
                    if(in[edge[top][i]]==0) q.push(edge[top][i]);
                }
            }
            for(i=ans.size()-1;i>=0;i--)
            {
                if(i!=ans.size()-1) printf(" ");
                printf("%d",ans[i]);
            }
            printf("
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    springboot + mybatis + 多数据源
    Git 常见问题汇总
    Git 常见问题汇总
    sqlserver存储过程实现多表分页
    bzoj5248(洛谷4363)(2018九省联考)一双木棋
    bzoj4033 [HAOI2015]树上染色
    bzoj3195 [Jxoi2012]奇怪的道路
    bzoj1426(洛谷4550)收集邮票
    bzoj4806 炮
    bzoj1090(SCOI2003)字符串折叠
  • 原文地址:https://www.cnblogs.com/2018zxy/p/10107837.html
Copyright © 2011-2022 走看看