【動態規劃】關鍵子工程

來源:互聯網
上載者:User
在大型工程的施工前,我們把整個工程劃分為若干個子工程,並把這些子工程編號為1、2、……、N;這樣劃分之後,子工程之間就會有一些依賴關係,即一些子工程必須在某些子工程完成之後才能施工。由於子工程之間有相互依賴關係,因此有兩個任務需要我們去完成:首先,我們需要計算整個工程最少的完成時間;同時,由於一些不可預測的客觀因素會使某些子工程延期,因此我們必須知道哪些子工程的延期會影響整個工程的延期,我們把有這種特徵的子工程稱為關鍵子工程,因此第二個任務就是找出所有的關鍵子工程,以便集中精力管理好這些子工程,盡量避免這些子工程延期,達到用最快的速度完成整個工程。為了便於編程,現在我們假設: (1)根據預算,每一個子工程都有一個完成時間。 (2)子工程之間的依賴關係是:部分子工程必須在一些子工程完成之後才開工。 (3)只要滿足子工程間的依賴關係,在任何時刻可以有任何多個子工程同時在施工,也既同時施工的子工程個數不受限制。 (4)整個工程的完成是指:所有子工程的完成。 例如,有五個子工程的工程規劃表: 序號    完成時間  子工程1  子工程2  子工程3  子工程4  子工程5 子工程1       5       -       0       0       0       0子工程2       4       0       -       0       0       0子工程3      12       0       0       -       0       0子工程4       7       1       1       0       -       0子工程5       2       1       1       1       1       -其中,表格中第 I+1 行 J+2 列的值如為 0 表示“子工程 I”可以在“子工程 J”沒完成前施工,為 1 表示“子工程 I”必須在“子工程 J”完成後才能施工。上述工程最快完成時間為 14 天,其中子工程1、3、4、5為關鍵子工程。  又例如,有五個子工程的工程規劃表: 序號  完成時間  子工程1  子工程2  子工程3  子工程4  子工程5 子工程1     5       -       0       1       0       0子工程2     4       0       -       0       0       0子工程3    12       0       0       -       1       0子工程4     7       1       1       0       -       0 子工程5     2       1       1       1       1       -上述的子工程劃分不合理,因為無法安排子工程1,3,4的施工。  輸入資料: 第 1 行為N,N是子工程的總個數,N≤200。 第2 行為N個正整數,分別代表子工程1、2、……、N的完成時間。 第 3 行到 N+2 行,每行有 N-1 個 0 或 1。其中的第 I+2 行的這些 0,1,分別表示“子工程 I”與子工程1、2、…、I-1、I+1、…N的依賴關係,(I=1、2、……、N)。每行資料之間均用一個空格分開。  輸出資料:  如子工程劃分不合理,則輸出-1; 如子工程劃分合理,則用兩行輸出:第1行為整個工程最少的完成時間。第2行為按由小到大順序輸出所有關鍵子工程的編號。  範例: 輸入檔案名稱:project.in 5                               5 4 12 7 2                   0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1  輸出檔案名:project.out 14 1 3 4 5 

可用記憶化搜尋或者拓撲排序解決。
狀態:用f[i]表示完成i所需的最小時間及等待時間。
轉移方程:f[i] = max(f[j]) + t[i],其中,j是i的前驅結點。
ACCode:

#include <cstdio>#include <cstring>#include <cstdlib>#include <bitset>using std::bitset;using std::max;const char fi[] = "project.in";const char fo[] = "project.out";const int maxN = 210;struct Edge{int dest; Edge *next; };Edge *edge[maxN];int f[maxN];int t[maxN];int Ou[maxN];bitset <maxN> key;bitset <maxN> marked;int n, ok;  void init_file()  {    freopen(fi, "r", stdin);    freopen(fo, "w", stdout);  }    void insert(int u, int v)  {    Edge *p = new Edge;    p -> dest = v;    p -> next = edge[u];    edge[u] = p;  }    void readdata()  {    scanf("%d", &n);    for (int i = 1; i < n + 1; ++i)      scanf("%d", t + i);    for (int i = 1; i < n + 1; ++i)     for (int j = 1; j < n + 1; ++j)      if (i != j)      {        scanf("%d", &ok);        if (ok) {insert(i, j); ++Ou[j]; }      }    for (int i = 1; i < n + 1; ++i)     if (Ou[i] == 0) insert(0, i);  }    void DP(int u)  {    if (f[u]) return; //要記憶化。    marked.set(u);    for (Edge *p = edge[u]; p; p = p -> next)    {      int v = p -> dest;      if (marked.test(v))        {printf("-1"); exit(0); }//判斷是否存在環。      DP(v);      f[u] = max(f[u], f[v]);    }    f[u] += t[u];    marked.reset(u); //要記得清空標記。  }  void Find(int u)  {    int Max = 0;    for (Edge *p = edge[u]; p; p = p -> next)      Max = max(Max, f[p -> dest]);    for (Edge *p = edge[u]; p; p = p -> next)     if (f[p -> dest] == Max)       {key.set(p -> dest); Find(p -> dest); }  }    void work()  {    DP(0);    Find(0);    printf("%d\n", f[0]);    for (int i = 1; i < n + 1; ++i)     if (key.test(i)) printf("%d ", i);  }  int main(){  init_file();  readdata();  work();  exit(0);}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.