图论三:拓扑排序

一、基本知识

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("\n");
    }
    return 0;
}
View Code

 

posted @ 2018-12-12 15:02  麟阁  阅读(334)  评论(0编辑  收藏  举报