日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

关键路径 详解 (前置知识:拓扑排序)

發(fā)布時(shí)間:2023/12/14 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关键路径 详解 (前置知识:拓扑排序) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

圖論之關(guān)鍵路徑講解

回顧所需知識:

拓?fù)渑判?/h2>

對一個(gè)有向無環(huán)圖(Directed Acyclic Graph簡稱DAG)G進(jìn)行拓?fù)渑判?#xff0c;是將G中所有頂點(diǎn)排成一個(gè)線性序列,使得圖中任意一對頂點(diǎn)u和v,若邊(u,v)∈E(G),則u在線性序列中出現(xiàn)在v之前。

拓?fù)渑判?strong>對應(yīng)施工的流程圖具有特別重要的作用,它可以決定哪些子工程必須要先執(zhí)行,哪些子工程要在某些工程執(zhí)行后才可以執(zhí)行。為了形象地反映出整個(gè)工程中各個(gè)子工程(活動)之間的先后關(guān)系,可用一個(gè)有向圖來表示,圖中的頂點(diǎn)代表活動(子工程),圖中的有向邊代表活動的先后關(guān)系,即有向邊的起點(diǎn)的活動是終點(diǎn)活動的前序活動,只有當(dāng)起點(diǎn)活動完成之后,其終點(diǎn)活動才能進(jìn)行。

通常,我們把這種頂點(diǎn)表示活動、邊表示活動間先后關(guān)系的有向圖稱做頂點(diǎn)活動網(wǎng)(Activity On Vertex network),簡稱AOV網(wǎng)

一個(gè)AOV網(wǎng)應(yīng)該是一個(gè)有向無環(huán)圖,即不應(yīng)該帶有回路,因?yàn)槿魩в谢芈?#xff0c;則回路上的所有活動都無法進(jìn)行(對于數(shù)據(jù)流來說就是死循環(huán))。在AOV網(wǎng)中,若不存在回路,則所有活動可排列成一個(gè)線性序列,使得每個(gè)活動的所有前驅(qū)活動都排在該活動的前面,我們把此序列叫做拓?fù)湫蛄?Topological order),由AOV網(wǎng)構(gòu)造拓?fù)湫蛄械倪^程叫做拓?fù)渑判?Topological sort)。

AOV網(wǎng)的拓?fù)湫蛄胁皇俏ㄒ坏?#xff0c;滿足上述定義的任一線性序列都稱作它的拓?fù)湫蛄小?/p>

拓?fù)渑判虻膶?shí)現(xiàn)步驟※

  • 在有向圖中選一個(gè)沒有前驅(qū)的頂點(diǎn)并且輸出
  • 從圖中刪除該頂點(diǎn)和所有以它為尾的弧 (白話就是:刪除所有和它有關(guān)的邊)
  • 重復(fù)上述兩步,直至所有頂點(diǎn)輸出,循環(huán)結(jié)束后,若輸出的頂點(diǎn)數(shù)小于網(wǎng)中的頂點(diǎn)數(shù),則輸出“有回路”信息,否則輸出的頂點(diǎn)序列就是一種拓?fù)湫蛄小?/li>

    因此,也可以通過拓?fù)渑判騺砼袛嘁粋€(gè)圖是否有環(huán)。

    AOE網(wǎng)介紹

    AOE-網(wǎng)只是比AOV-網(wǎng)多了一個(gè)邊的權(quán)重,而且AOV-網(wǎng)一般是設(shè)計(jì)一個(gè)龐大的工程各個(gè)子工程實(shí)施的先后順序,而我們的AOE-網(wǎng)就是不僅僅關(guān)系整個(gè)工程中各個(gè)子工程的實(shí)施的先后順序,同時(shí)也關(guān)系整個(gè)工程完成最短時(shí)間。

    通常在AOE網(wǎng)中列出完成預(yù)定工程計(jì)劃所需要進(jìn)行的活動,每個(gè)活動計(jì)劃完成的時(shí)間,要發(fā)生哪些事件以及這些事件與活動之間的關(guān)系,從而可以確定該項(xiàng)工程是否可行,估算工程完成的時(shí)間以及確定哪些活動是影響工程進(jìn)度的關(guān)鍵

    AOE網(wǎng)特點(diǎn)

    AOE-網(wǎng)還有一個(gè)特點(diǎn)就是:只有一個(gè)起點(diǎn)(入度為0的頂點(diǎn))和一個(gè)終點(diǎn)(出度為0的頂點(diǎn)),并且AOE-網(wǎng)有兩個(gè)待研究的問題:
    1、完成整個(gè)工程需要的時(shí)間
    2、哪些活動是影響工程進(jìn)度的關(guān)鍵

    關(guān)鍵路徑介紹

    關(guān)鍵路徑:AOE-網(wǎng)中,從起點(diǎn)到終點(diǎn)最長的路徑的長度(長度指的是路徑上邊的權(quán)重和)
    關(guān)鍵活動
    假設(shè)起點(diǎn)是vo,則我們稱從v0到vi的最長路徑的長度為vi的最早發(fā)生時(shí)間
    同時(shí),vi的最早發(fā)生時(shí)間也是所有以vi為尾的弧所表示的活動的最早開始時(shí)間
    使用e(i)表示活動ai最早發(fā)生時(shí)間,除此之外,我們還定義了一個(gè)活動最遲發(fā)生時(shí)間,使用l(i)表示,不推遲工期的最晚開工時(shí)間。我們把e(i)=l(i)的活動ai稱為關(guān)鍵活動,因此,這個(gè)條件就是我們求一個(gè)AOE-網(wǎng)的關(guān)鍵路徑的關(guān)鍵所在了。

    求關(guān)鍵路徑的步驟

  • 輸入頂點(diǎn)數(shù)和邊數(shù),已經(jīng)各個(gè)弧的信息建立圖
  • 從源點(diǎn)v1出發(fā),令ve[0]=0;按照拓?fù)湫蛄型扒蟾鱾€(gè)頂點(diǎn)的ve。如果得到的拓?fù)湫蛄袀€(gè)數(shù)小于網(wǎng)的頂點(diǎn)數(shù)n,說明我們建立的圖有環(huán),無關(guān)鍵路徑,直接結(jié)束程序
  • 從終點(diǎn)vn出發(fā),令vl[n-1]=ve[n-1],按逆拓?fù)湫蛄?#xff0c;往后求其他頂點(diǎn)vl值
  • 根據(jù)各個(gè)頂點(diǎn)的ve和vl求每個(gè)弧的e(i)和l(i),如果滿足e(i)=l(i),說明是關(guān)鍵活動。
  • 代碼實(shí)現(xiàn)

    例題
    SDUT2498

    #include<bits/stdc++.h>using namespace std;const int M = 5e4 + 5;struct N {int in, out, weight; }edge[M]; //用結(jié)構(gòu)體表示邊int node[M]; //記錄經(jīng)過的節(jié)點(diǎn) int distant[M]; //記錄最長路徑 int degree_in[M]; //記錄每個(gè)點(diǎn)的入度 目的是尋找源點(diǎn)(沒有入度的點(diǎn)) int sourcepoint; //源點(diǎn) void bellman(int point_number, int edge_number) {memset(node, 0, sizeof(node));memset(distant, 0, sizeof(distant));for (int k = 2; k <= point_number; k++) { //除去源點(diǎn),只需要進(jìn)行(點(diǎn)的數(shù)量-1)次求值int flag = 0; //每次找下一個(gè)點(diǎn)的時(shí)候都會重置flagfor (int i = 1; i <= edge_number; i++) { //動態(tài)規(guī)劃,找K次,每次都更新源點(diǎn)的權(quán)值,最后源點(diǎn)的權(quán)值最大,輸出的就是最大路徑if ((distant[edge[i].in] < distant[edge[i].out] + edge[i].weight) || ((distant[edge[i].in] == distant[edge[i].out] + edge[i].weight) && (edge[i].out < node[edge[i].in]))) {distant[edge[i].in] = distant[edge[i].out] + edge[i].weight; //把權(quán)值放到每條邊的起點(diǎn)上,最后輸出源點(diǎn)的權(quán)值node[edge[i].in] = edge[i].out;flag = 1;}}if (flag == 0) { //如果flag沒更新,說明循環(huán)每條邊的時(shí)候找不到比原來的權(quán)值更大的路徑了,跳出循環(huán)即可break; //這時(shí)候源點(diǎn)處已經(jīng)找到了最大權(quán)值}}printf("%d\n", distant[sourcepoint]); //跳出循環(huán)后,輸出最終結(jié)果while (node[sourcepoint] != 0) {printf("%d %d\n", sourcepoint, node[sourcepoint]);sourcepoint = node[sourcepoint];} }int main() {int point_number, edge_number;int sv, ev, w;while (~scanf("%d%d", &point_number, &edge_number)) {memset(edge, 0, sizeof(edge)); //多組數(shù)據(jù)輸入時(shí) 初始化很重要memset(degree_in, 0, sizeof(degree_in));for (int i = 1; i <= edge_number; i++) {scanf("%d%d%d", &sv, &ev, &w);edge[i].in = sv; //每條邊的入度、出度、權(quán)重edge[i].out = ev;edge[i].weight = w;degree_in[ev]++; //每個(gè)點(diǎn)的入度}for (int i = 1; i <= point_number; i++) { //尋找源點(diǎn)if (degree_in[i] == 0) { //入度為零的點(diǎn)為源點(diǎn)sourcepoint = i;} }bellman(point_number, edge_number);}return 0; }

    看不懂的可以自取視頻理解,多看兩遍就差不多了

    總結(jié)

    以上是生活随笔為你收集整理的关键路径 详解 (前置知识:拓扑排序)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。