活動網路(Activity Network)

My vault 資料結構筆記:活動網路(Activity Network)。

AOV(Activity on Vertex)

  • 定義:AOV 網路是有向圖 $G$。頂點=任務或活動;邊=先後關係。

  • 前驅 / 後繼:若從 $i$ 有有向路徑到 $j$,則 $i$ 是 $j$ 的前驅,$j$ 是 $i$ 的後繼。

  • 直接前驅:若邊 $\langle i,j\rangle\in E$,則 $i$ 為 $j$ 的「直接前驅」。

  • 遞移(transitive):若 $i\to j$ 且 $j\to k$,則 $i\to k$。

  • 反自反(irreflexive):對所有 $i$,不成立 $i\to i$。

  • 偏序(partial order):同時具備「傳遞」與「反自反」的先後關係。

  • 可行性:若網路無有向環(即為 DAG),則可行。

拓撲序(Topological Order)

  • 定義:一個線性序,使得任意兩頂點 $i,j$,若 $i$ 是 $j$ 的前驅,則 $i$ 在序中先於 $j$。

  • 一個 AOV 可能有多個拓撲序。

拓撲排序

目標:輸出一個拓撲序;若偵測到環則回報「不可行」。

資料結構:

  • 以adj list表示圖;每個頂點保留in-degree 計數(count)。

  • 維護一個堆疊存放入度為 $0$ 的頂點。

步驟:

  1. 計算所有頂點的 in-degree。將 in-degree $=0$ 的頂點依序推入堆疊 $S$。

  2. 重複 $n$ 次:

    • 若 $S$ 為空,則每個頂點都有前驅 ⇒ 圖含環 ⇒ 報告失敗。

    • 否則彈出一頂點 $j$ 並輸出之;

    • 對 $j$ 的每個後繼 $k$:將 $k$ 的入度 $count[k]{-}{-}$;若變為 $0$,則把 $k$ 推入 $S$。

  3. 全部輸出完即得一個拓撲序。

時間複雜度:$O(e+n)$。空間:鄰接表與計數陣列 $O(e+n)$。 01-拓撲排序 - 全部輸出完即得一個拓撲序。

參考樣式(貼近課本 C 風格)

void topsort(Graph g, int n){
  int i, j, k; Node* p;
  int top = -1;              // 堆疊 top(用整數鏈結法)
  for(i=0;i<n;i++)           // 建立初始堆疊:入度為 0 的頂點
    if(g[i].count==0){ g[i].count = top; top = i; }

  for(i=0;i<n;i++){
    if(top==-1){ error("Network has a cycle"); return; }
    j = top;                 // 彈出
    top = g[top].count;
    print(j);                // 輸出 j
    for(p=g[j].link; p; p=p->link){
      k = p->vertex;
      if(--g[k].count==0){   // 新成為入度 0
        g[k].count = top;
        top = k;             // 推入堆疊
      }
    }
  }
}

AOE (Activity on Edge)

  • 模型:頂點=事件;邊=活動;權重 $w_{uv}$=工期;必要時加「虛擬活動」(工期 $0$)表額外依賴。

  • 目標:專案最短完工時間、關鍵路徑、各活動最早/最遲時刻與浮時。

  • 流程(先取事件的拓撲序):

    • 正向傳播(最早事件時間):$ve[s]=0$,$ve[v]=\max_{(u,v)\in E}(ve[u]+w_{uv})$;工期 $T^*=ve[t]$。

    • 反向傳播(最遲不延誤時間):$vl[t]=T^*$,$vl[u]=\min_{(u,v)\in E}(vl[v]-w_{uv})$。

    • 活動指標:

      • 最早開工 $e_{uv}=ve[u]$。

      • 最遲開工 $l_{uv}=vl[v]-w_{uv}$。

      • $s_{uv}=l_{uv}-e_{uv}=(vl[v]-w_{uv})-ve[u]$。

    • 關鍵活動與路徑:$s_{uv}=0$ 的邊與其連成的 $s\to t$ 路徑(可多條)。

  • 複雜度:鄰接表+拓撲序實作皆為 $O(|V|+|E|)$。

範例

02-範例

  • Q3|Critical task 判定

    • 定義:位於任一關鍵路徑的活動;浮時 $s=0$。

    • 作法:跑 CPM,找所有邊 $(u,v)$ 使 $s_{uv}=0$。

    • 例:關鍵路徑 $A1\to a4 \to a7\to a10$、$A1\to a4 \to a8\to a11$
      → critical tasks $={A1,a4,a7,a8,a10,a11}$。

  • Q4|縮短工期要加速哪裡

    • 先列出全部關鍵路徑,取其交集=bottleneck tasks。

    • 只要縮短交集中的活動,專案總工期一定下降;只縮某一路徑上的非交集活動,可能不降。

  • Q5|哪些活動可延遲?可延遲多久

    • 非 critical task 可延遲;可延遲量=浮時 $s$。

    • 事件最早時間(正向):

      • $ee(s)=0$

      • $ee(v)=\max_{(u,v)\in E}\big(ee(u)+w_{uv}\big)$

    • 事件最遲時間(反向):

      • $T^=ee(t)$,$le(t)=T^$

      • $le(u)=\min_{(u,v)\in E}\big(le(v)-w_{uv}\big)$

      • 例:$le(y)=15,\ le(z)=16,\ w_{xy}=6,\ w_{xz}=10 \Rightarrow le(x)=\min(15-6,16-10)=6$

    • 活動指標與浮時:

      • 最早開工:$e_{uv}=ee(u)$

      • 最遲開工:$l_{uv}=le(v)-w_{uv}$

      • 浮時:$s_{uv}=l_{uv}-e_{uv}=(le(v)-w_{uv})-ee(u)$

      • 例:$ee(x)=5$,若某活動 $l=7$,則 $s=7-5=2$(可延 2 天不影響完工)