图论-拓扑排序

Posted sweetlittlebaby

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图论-拓扑排序相关的知识,希望对你有一定的参考价值。

学离散的偏序关系时的一个应用,

问题:小方准备组织一次演讲比赛,有如下环节(未排序):

- 进行彩排

- 确定演讲主题

- 租借服装

- 确定比赛时间

- 确定比赛地点

- 确定参赛人员

- 申请经费

- 确定嘉宾人选

- 购买奖品,装饰物

- 比赛啦~

但是:

- 确定演讲主题之后才能确定比赛时间;

- 确定主题之后才能准备申请经费

- 在确定选手是否能参加之前先要确定比赛时间

- 购买何种装饰物需由比赛地点确定

- 只有当选手确定之后,才能去借服装,租场地和确定要邀请的嘉宾

- 如果申请经费没有成功,那么不能去购买奖品和装饰品

- 在彩排之前需要借服装和确定地点

- 比赛只有当嘉宾都邀请成功,已购买奖品而且彩排过才能进行

 

这些环节之间有一些约束关系,那么该怎么办呢;

画偏序关系的哈斯图形式(方案可能有多种):

{

     偏序关系:(自反性,反对称性,传递性)

     哈斯图的画法:

      1,删除自环;

      2,具有传递性的,删掉可直达的

      3,重组位置,使得有向的箭头指向正上方或斜上方。

}

拓扑排序(topologicalSorting):

输入:偏序集(A,R)

输出:A的元素在<意义下“从小到大”逐一列出所形成的序列

1,      B<- A,S<-R,List<-空

2,      while|B|>0 do

2.1,     从B中选择一个极小元x加入队列list

2.2,    B<- B- {x}

2.3,    S<- S|B

3,      return list

 

维基百科上关于Kahn算法的伪码描述:

 

L← Empty list that will contain the sorted elements
S ← Set of all nodes with no incoming edges
while S is non-empty do
    remove a node n from S
    insert n into L
    foreach node m with an edge e from nto m do
        remove edge e from the graph
        if m has no other incoming edges then
            insert m into S
if graph has edges then
    return error (graph has at least onecycle)
else 
    return L (a topologically sortedorder)

 

算法:(kahn)

对于一个有向无环图(DAG)来说:

1), 统计所有节点的入度,对于入度为0的节点就可以分离出来,然后将这个节点指向所有节点的入度减去1;

2), 重复1),知道所有的节点都被分离出来,拓扑排序结束。

3), 如果最后不存在入度为0的节点,那就说明图有环,无解。

注:对于入度为0的节点,则这个节点没有前驱,只要不是孤立节点,那么完成这个节点之后,对于它的所有后继节点来说,前驱结点就完成了一个,入度进行-1。

技术图片

 

伪代码:(kahn)

bool toposort() {
    q = new queue();
    for (i = 0; i < n; i++)
        if (in_deg[i] == 0) q.push(i);
    ans = new vector();
    while (!q.empty()) {
        u = q.pop();
        ans.push_back(u);
        for each edge(u, v) {
            if (--in_deg[v] == 0) q.push(v);
        }
    }
    if (ans.size() == n) {
        for (i = 0; i < n; i++)
            std::cout << ans[i] << std::endl;
        return true;
    } else {
        return false;
    }
}

拓扑排序的阶过不唯一,所以一般会按某种要求进行输出,就需要用到优先队列,按字典序输出:

 1 vector<int> head[maxn],ans;
 2 int n,m,in[maxn];
 3 void topologicalsorting()
 4 {
 5     cin>>n>>m;
 6     for(int i=0; i<m; i++)
 7     {
 8         int u,v;
 9         scanf("%d%d",&u,&v);
10         head[u].push_back(v);
11         in[v]++;
12     }
13     priority_queue<int,vector<int>,greater<int> > q;
14     for(int i=1; i<=n; i++)
15     {
16         if(!in[i])
17         {
18             q.push(i);
19         }
20     }
21     while(q.empty()&&ans.size()<n)
22     {
23         int v=q.top();
24         q.pop();
25         ans.push_back(v);
26         for(int i=0; i<head[v].size(); i++)
27         {
28             in[head[v][i]]--;
29             if(!in[head[v][i]])
30              q.push(head[v][i]);
31         }
32     }
33     if(ans.size()==n)
34     {
35         //找到了排序
36     }
37     else
38     {
39         //图里有自环;
40     }
41     
42 } 

算法:(DFS)

DFS版本:

 

 1 // dfs 版本
 2 bool dfs(int u) {
 3   c[u] = -1;
 4   for (int v = 0; v <= n; v++)
 5     if (G[u][v]) {
 6       if (c[v] < 0)
 7         return false;
 8       else if (!c[v])
 9         dfs(v);
10     }
11   c[u] = 1;
12   topo.push_back(u);
13   return true;
14 }
15 bool toposort() {
16   topo.clear();
17   memset(c, 0, sizeof(c));
18   for (int u = 0; u <= n; u++)
19     if (!c[u])
20       if (!dfs(u)) return false;
21   reverse(topo.begin(), topo.end());
22   return true;
23 }

 

 

考虑一个图,删掉某个入度为  的节点之后,如果新图可以拓扑排序,那么原图一定也可以。反过来,如果原图可以拓扑排序,那么删掉后也可以。

 

练习:

1,判断自环问题:链接

题意:就裸拓扑排序,判断一下自环;

code:

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 1e5+10;
 4 vector<int> G[maxn];
 5 int in[maxn];
 6 int n,m;
 7 int sum;
 8 queue<int> q;
 9 int toposort()
10 {
11     while(!q.empty())
12      q.pop();
13     sum=0;
14     for(int i=1; i<=n; i++)
15      if(!in[i])
16       q.push(i);
17     while(!q.empty())
18     {
19         int v=q.front();
20         q.pop();
21         sum++;
22         for(int i=0; i<G[v].size(); i++)
23         {
24             in[G[v][i]]--;
25             if(!in[G[v][i]])
26              q.push(G[v][i]);
27         }
28     }
29     if(sum==n)
30      return 1;
31     else
32     {
33         return 0;
34     }
35     
36 }
37 int main()
38 {
39     int t;
40     cin>>t;
41     while(t--)
42     {
43         cin>>n>>m;
44         memset(G,0,sizeof(G));
45         memset(in,0,sizeof(in));
46         for(int i=1; i<=m; i++)
47         {
48             int u,v;
49             cin>>u>>v;
50             G[u].push_back(v);
51             in[v]++;
52         }
53         if(toposort())
54          cout<<"Correct"<<endl;
55         else
56         {
57             cout<<"Wrong"<<endl;
58         }
59         
60     }
61     //system("pause");
62     return 0;
63 }

 

2,同1,判断自环,注意范围变了,从0~n-1;(HDU3342

code:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 1e5+10;
 4 vector<int> G[maxn];
 5 int in[maxn];
 6 int n,m;
 7 int sum;
 8 queue<int> q;
 9 int toposort()
10 {
11     while(!q.empty())
12      q.pop();
13     sum=0;
14     for(int i=0; i<n; i++)
15      if(!in[i])
16       q.push(i);
17     while(!q.empty())
18     {
19         int v=q.front();
20         q.pop();
21         sum++;
22         for(int i=0; i<G[v].size(); i++)
23         {
24             in[G[v][i]]--;
25             if(!in[G[v][i]])
26              q.push(G[v][i]);
27         }
28     }
29     if(sum==n)
30      return 1;
31     else
32     {
33         return 0;
34     }
35     
36 }
37 int main()
38 {
39     
40     while(cin>>n>>m)
41     {
42         if(!n&&!m)
43          break;
44         memset(G,0,sizeof(G));
45         memset(in,0,sizeof(in));
46         for(int i=1; i<=m; i++)
47         {
48             int u,v;
49             cin>>u>>v;
50             G[u].push_back(v);
51             in[v]++;
52         }
53         if(toposort())
54          cout<<"YES"<<endl;
55         else
56         {
57             cout<<"NO"<<endl;
58         }
59     }
60     system("pause");
61     return 0;
62 }

 

以上是关于图论-拓扑排序的主要内容,如果未能解决你的问题,请参考以下文章

图论排序---拓扑排序

图论_拓扑排序

图论基础——邻接链表存图+拓扑排序

图论专题拓扑排序

图论-拓扑排序-应用

操作系统 & 图论传参一个AOE图,得到按其拓扑排序及权值执行临界区代码的线程数组