1. 程式人生 > >算法入門經典第六章 例題6-15 給任務排序

算法入門經典第六章 例題6-15 給任務排序

訪問 images 技術 pan 是什麽 style efi 開始 max

假設有n個變量,還有m個二元組(u,v),分別表示變量u小於v。那麽,所有變量從小到大排列起來應該是什麽樣子呢?例如,有4個變量a,b,c,d,若已知a<b,c<b,d<c,則這4個變量的排序可能是a<d<c<b。盡管還有其他可能(如d<a<c<b),你只需找出其中一個即可。

Sample Input

5 4

1 2

2 3

1 3

1 5

0 0

Sample Output

1 4 2 5 3

題意:假設有n個變量,還有m個二元組(u,v),分別表示變量u小於v。那麽,所有變量從小到大排列起來應該是什麽樣子的呢?

把每個變量看成一個點,“小於”關系看成有向邊,則得到了一個有向圖。這樣,我們的任務實際上是把一個圖的所有結點排序,使得每一條有向邊(u,v)對應的u都排在v的前面。

用dfs完成拓撲排序,在訪問完一個結點之後吧它加到當前拓撲序的首部。

#include<stdio.h> 
#include<stdlib.h> 
#include<string.h> 
#include<math.h> 
#define max 100+5 
int c[max],topo[max],t,n,G[max][max]; 
//如G[1,2] 從1指向2的有向線段 int dfs(int u) { int v; c[u] = -1; //訪問標誌,-1為正在訪問,0是未訪問,1是已經訪問 for(v = 1; v <= n; v++) //看的是與你比較的v 有無再次訪問到 if(G[u][v]) { if(c[v] < 0) return 0; // 如果再次訪問到一個在c中被標記為-1的結點就說明存在一個有向環 else if(!c[v] && !dfs(v)) return 0; //v沒被訪問過 用dfs遞歸 如果返回0表示失敗 } c[u] = 1; topo[
--t] = u; return 1; } int toposort() { int i; t = n; memset(c,0,sizeof(c)); for(i = 1; i <= n; i++) if(!c[i] && !dfs(i)) return 0; return 1; } int main() { int m,i; while(scanf("%d%d",&n,&m),n || m) { int u,v; memset(G,0,sizeof(G)); for(i = 0 ; i < m ; i++) { scanf("%d%d",&u,&v); G[u][v] = 1; } if(toposort()) { for(i = 0; i < n-1; i++) printf("%d ",topo[i]); printf("%d\n",topo[i]); } } return 0; }

【分析】

題目中n個變量看成圖中n個結點,圖中的邊即是二元關系,m個二元組就代表了這m條邊表示的二元關系,(u,v)表示v大於u,從u向v連一條有向邊,如果這m個二元
組不矛盾,那麽這個圖便是一個DAG否則就存在一個有向環,解便不存在了,舉個例子a<b,b<c,可以推出a<c,但是現在出現了c連到了a意思是a>c,與之前的遞推相
悖,所以如果圖中存在有向環,則不存在拓撲序,反之一個DAG圖就存在拓撲序,拓撲序可以用DFS求。從圖中的某個結點開始,用一個c數組標記,-1表示這個結點正
在訪問,那麽如果再次訪問到一個在c中被標記為-1的結點就說明存在一個有向環,0表示這個結點還未被訪問,它的子孫有沒有被訪問不知道,因為有可能從它的子孫
開始DFS,1表示這個結點以及它的子孫已經被訪問過,每次DFS在訪問完一個結點後把它加到當前拓撲序首部,因為只能保證向後已經訪問完,我們不知道開始DFS的
結點是否有父結點,所以如果前面還有結點肯定都比現在訪問到的這些結點要小必須放在它們前面。

【拓展】

有向無環圖(Directed Acyclic Graph, DAG)是有向圖的一種,字面意思的理解就是圖中沒有環。常常被用來表示事件之間的驅動依賴關系,管理任務之間的調度。拓撲排序是對DAG的頂點進行排序,使得對每一條有向邊(u, v),均有u(在排序記錄中)比v先出現。亦可理解為對某點v而言,只有當v的所有源點均出現了,v才能出現。

下圖給出有向無環圖的拓撲排序:

技術分享

DFS

在DFS中,依次打印所遍歷到的頂點;而在拓撲排序時,頂點必須比其鄰接點先出現。在下圖中,頂點5比頂點0先出現,頂點4比頂點1先出現。

技術分享

在DFS實現拓撲排序時,用來保存拓撲排序的頂點序列;並且保證在某頂點入棧前,其所有鄰接點已入棧

算法入門經典第六章 例題6-15 給任務排序