拓撲排序

拓撲排序&關鍵路徑

前言

今天開始學習拓撲排序和關鍵路徑,寫個博客記錄一下qwqphp

目錄

  • 知識講解html

  • 題目模型node

  • 算法框架c++

  • 例題講解算法

  • 習題推薦網絡


知識搬運

在介紹拓撲排序以前,咱們來引入一下框架

  • 有向無環圖

顧名思義,若是一個有向圖的任意頂點都沒法經過一些有向邊回到自身,那麼就稱這個圖爲有向無環圖(DAG)ide

  • 拓撲序列

爲了能更好地理解拓撲排序是什麼,咱們先經過一個栗子來感覺一下:學習

若是你想說一口流利的英語,那你須要先學英語口語

若是你想學英語口語,那你須要多讀英語文章

若是你想讀英語文章,那你須要學習不少英語單詞

綜上,你能說一口流利英語的全過程以下(一本正經 ):spa

學習英語單詞->多讀英語文章->鍛鍊英語口語->流利的英語

這樣的一個順序序列就是拓撲序列

  • 拓撲排序

簡單來講,求得如上拓撲序列的過程就叫作拓撲排序

說得完整一點:將有向無環圖\(G\)的全部頂點排成一個線性序列,使得對圖\(G\)中的任意兩個頂點\(u\)\(v\),若是存在一條邊\(<u,v>\),那麼在這個線性序列中,\(u\)必定在\(v\)的前面的過程就叫作拓撲排序

  • 做用&補充
  1. 由於單個任務之間可能存在多個並列關係,因此拓撲序列並非惟一的

  2. 若是圖\(G\)中存在環,那麼拓撲排序後獲得的序列元素個數將不等於原始元素個數\(N\),因此咱們能夠經過這個特色去判斷一個圖是否有環

  3. 生活中許多大型項目都是分步驟完成的,因此拓撲排序能夠說是對此應運而生,經過求拓撲序列能夠肯定每一個子任務的最先完成時間和最晚完成時間(也能夠求得圖\(G\)最長路徑

  4. 其實拓撲排序更多地是和其餘算法搭配使用,解決的問題也更復雜,因此必定要理解到拓撲排序的實質,不能只懂表面

  • 關鍵路徑

這個內容吧..說實話感受就是提煉出的兩種模型:\(AOV\)網和\(AOE\)

拓撲排序加點其餘算法就能搞定,就不細講了(多是我理解錯誤,歡迎你們指出)


題目模型

給定\(N\)個子任務以及任務之間的前後關係(能夠推得並列關係)

  1. 要求解決整個問題的最短期

  2. 要求求出每一個子任務的最先開始時間

  3. 要求求出每一個子任務的最晚完成時間

算法框架

  1. 在輸入邊時,存儲並統計每一個點的入度

  2. 全部入度爲0的點裝入一個隊列(能夠是普通隊列,也能夠是優先隊列,主要看題目需求)

  3. 從隊列中取出對首元素\(x\),遍歷全部與\(x\)相連的點\(v\),再將\(v\)的入度減一,若是減後\(v\)的入度變爲0,則將\(v\)也入隊

  4. 重複3的操做直到隊列爲空

最終的拓撲序列就是取出的\(x\)的順序


例題講解

純純的板子題,不過題目有點坑,必需要用\(stack\)才能經過(題目要求..大霧)

本題是多組數據啊,其餘的也就是板子題了,多刷點這種無腦題板子就敲熟了

來掛一發板子(使用鏈式前向星存圖,固然\(vector\)也行啊):

#include <bits/stdc++.h>
using namespace std;
queue<int> q;
vector<int> ans;
int n,m,u,v,tot;
int in[510005],head[510005];

struct node {
	int to,net;
} e[510005];

inline void add(int u,int v) {
	e[++tot].to=v;
	e[tot].net=head[u];
	head[u]=tot;
}

int main() {
	scanf("%d%d",&n,&m);
	for(register int i=1;i<=m;i++) {
		scanf("%d%d%d",&u,&v);
		add(u,v);
		in[v]++;
	}
	for(register int i=1;i<=n;i++) {
		if(in[i]==0) q.push(i);
	}
	while(!q.empty()) {
		int x=q.front();
		q.pop();
		ans.push_back(x);
		for(register int i=head[x];i;i=e[i].net) {
			int v=e[i].to;
			in[v]--;
			if(in[v]==0) q.push(v);
		}
	}
	if(ans.size()==n) {
		for(register int i=0;i<ans.size();i++) printf("%d\n",ans[i]);
	}
	else puts("ERROR");
	return 0;
}

習題推薦

(stO 洛谷好啊 Orz)

  1. 求最長路徑除了可以使用拓撲排序求關鍵路徑外,還能夠取巧:

將邊權所有取相反數,將問題轉換爲求解最短路!

那麼咱們就可以用\(SPFA\)之類的算法輕鬆A掉(\(Dijkstra\)固然不能用啦,由於有負權)

  1. 這裏貼一下同桌dalao關於菜餚製做的題解

本題雖然是一道紫色的題,可是真的挺模板啊,感受比車站分級、神經網絡什麼的簡單多了

  1. 這裏再貼一發個人關於病毒Virus的題解
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息