7-11 關鍵活動(30 分)
假定一個工程項目由一組子任務構成,子任務之間有的可以並行執行,有的必須在完成了其它一些子任務后才能執行。“任務調度”包括一組子任務、以及每個子任務可以執行所依賴的子任務集。
比如完成一個專業的所有課程學習和畢業設計可以看成一個本科生要完成的一項工程,各門課程可以看成是子任務。有些課程可以同時開設,比如英語和C程序設計,它們沒有必須先修哪門的約束;有些課程則不可以同時開設,因為它們有先后的依賴關系,比如C程序設計和數據結構兩門課,必須先學習前者。
但是需要注意的是,對一組子任務,並不是任意的任務調度都是一個可行的方案。比如方案中存在“子任務A依賴於子任務B,子任務B依賴於子任務C,子任務C又依賴於子任務A”,那么這三個任務哪個都不能先執行,這就是一個不可行的方案。
任務調度問題中,如果還給出了完成每個子任務需要的時間,則我們可以算出完成整個工程需要的最短時間。在這些子任務中,有些任務即使推遲幾天完成,也不會影響全局的工期;但是有些任務必須准時完成,否則整個項目的工期就要因此延誤,這種任務就叫“關鍵活動”。
請編寫程序判定一個給定的工程項目的任務調度是否可行;如果該調度方案可行,則計算完成整個工程項目需要的最短時間,並輸出所有的關鍵活動。
輸入格式:
輸入第1行給出兩個正整數N(≤100)和M,其中N是任務交接點(即銜接相互依賴的兩個子任務的節點,例如:若任務2要在任務1完成后才開始,則兩任務之間必有一個交接點)的數量。交接點按1~N編號,M是子任務的數量,依次編號為1~M。隨后M行,每行給出了3個正整數,分別是該任務開始和完成涉及的交接點編號以及該任務所需的時間,整數間用空格分隔。
輸出格式:
如果任務調度不可行,則輸出0;否則第1行輸出完成整個工程項目需要的時間,第2行開始輸出所有關鍵活動,每個關鍵活動占一行,按格式“V->W”輸出,其中V和W為該任務開始和完成涉及的交接點編號。關鍵活動輸出的順序規則是:任務開始的交接點編號小者優先,起點編號相同時,與輸入時任務的順序相反。
輸入樣例:
7 8
1 2 4
1 3 3
2 4 5
3 4 3
4 5 1
4 6 6
5 7 5
6 7 2
輸出樣例:
17 1->2 2->4 4->6 6->7
思路:拓撲排序檢驗是否有環存在,然后用關鍵路徑來進行輸出—>多起點多終點和最大N,隨機,可行過不去。這個PTA平台好的地方就是你提交了還能知道自己錯在哪,要是在杭電碰到這題那才是真的絕望,按照之前的上課思維默認第一個點都是入度為零的起始節點,最后的結點為出度為零的終止結點,要是這樣子的話下面的這組數據輸出來的答案肯定是對不上的,於是我想到需要知道起始節點和終止結點,所以在這個題中我借助了change數組在topo函數中該拓撲排序序列,以解決多起點多終點和最大N時,序列號隨機且可行的情況。

#include<stdio.h> #include<limits.h> #include<queue> #include<string.h> #include<iostream> using namespace std; #define MAXN 200 typedef struct ArcNode{ int adjvex; //該弧所指向的頂點 int weight; //用於存儲權值 struct ArcNode *nextarc;//指向下一條弧的指針 }ArcNode; //表結點 typedef struct VNode{ int date; //頂點信息 int into; //該結點的入度 ArcNode *firstarc; //第一個表結點的地址,指向第一條依附該頂點的弧的指針 }VNode, AdjList[MAXN]; //頭結點 typedef struct { AdjList vertices; int vexnum; //頂點的數量 int arcnum; //弧的數量 }ALGraph; void CreateALGraph(ALGraph *Gp) { cin >> Gp->vexnum >> Gp->arcnum; for (int i = 1; i <= Gp->vexnum; i++) //初始化頂點信息 { Gp->vertices[i].date = i; Gp->vertices[i].into = 0; Gp->vertices[i].firstarc = NULL; } for (int i = 0; i < Gp->arcnum; i++) { int vi, vj, w; cin >> vi >> vj >> w; ArcNode *arc = new ArcNode; arc->adjvex = vj; arc->weight = w; arc->nextarc = Gp->vertices[vi].firstarc; Gp->vertices[vi].firstarc = arc; Gp->vertices[vj].into++; } } bool topo(ALGraph G) { queue<int>que; int sum = 0, flag[MAXN]; //flag用來標記已經輸出的頂點 memset(flag, 0, sizeof(flag)); for (int i = 1; i <= G.vexnum; i++) //把入度為0的頂點入棧 if (G.vertices[i].into == 0){ que.push(i); flag[i] = 1; } while (!que.empty()){ int temp = que.front(); //cout << temp << endl; sum++; que.pop(); ArcNode *pos = G.vertices[temp].firstarc; while (pos != NULL){ G.vertices[pos->adjvex].into--; pos = pos->nextarc; } for (int i = 1; i <= G.vexnum; i++) //把入度為0的頂點入棧 if (G.vertices[i].into == 0 && !flag[i]){ que.push(i); flag[i] = 1; } } return sum == G.vexnum ? true : false; } void CriticalPath(ALGraph G) { int ve[MAXN], vl[MAXN]; //************************ // 以下是求最早發生時間 //************************ for (int i = 1; i <= G.vexnum; i++) ve[i] = 0; for (int i = 1; i <= G.vexnum; i++) { ArcNode *pos = G.vertices[i].firstarc; while (pos != NULL){ int temp = pos->adjvex; if (ve[i] + pos->weight > ve[temp]) ve[temp] = ve[i] + pos->weight; pos = pos->nextarc; } } //*********************** //以下是求最遲發生時間 //*********************** int max = 0; for (int i = 1; i <= G.vexnum;i++) if (max < ve[i])max = ve[i]; cout << max << endl; for (int i = 1; i <= G.vexnum; i++) vl[i] = max; for (int i = G.vexnum; i >=1 ; i--) { ArcNode *pos = G.vertices[i].firstarc; while (pos != NULL){ int temp = pos->adjvex; if (vl[temp] - pos->weight < vl[i]) vl[i] = vl[temp] - pos->weight; pos = pos->nextarc; } } //****************************** for (int i = 1; i <= G.vexnum; i++) { ArcNode *pos = G.vertices[i].firstarc; while (pos != NULL){ int temp = pos->adjvex; int e = ve[i]; int l = vl[temp] - pos->weight; if (e == l) cout << i << "->" << temp << endl; pos = pos->nextarc; } } } int main() { ALGraph G; CreateALGraph(&G); if (!topo(G)){ cout << "0" << endl; return 0; } CriticalPath(G); return 0; }
輸入樣例: 7 8 3 1 1 3 2 2 1 4 4 2 4 3 4 6 2 4 7 2 6 5 2 7 5 2 輸出樣例: 9 1->4 2->4 3->2 3->1 4->7 4->6 6->5 7->5
以下是AC代碼:
#include<stdio.h> #include<limits.h> #include<queue> #include<string.h> #include<iostream> using namespace std; #define MAXN 200 typedef struct ArcNode{ int adjvex; //該弧所指向的頂點 int weight; //用於存儲權值 struct ArcNode *nextarc;//指向下一條弧的指針 }ArcNode; //表結點 typedef struct VNode{ int date; //頂點信息 int into; //該結點的入度 ArcNode *firstarc; //第一個表結點的地址,指向第一條依附該頂點的弧的指針 }VNode, AdjList[MAXN]; //頭結點 typedef struct { AdjList vertices; int vexnum; //頂點的數量 int arcnum; //弧的數量 }ALGraph; int change[MAXN]; //借此來保存拓撲排序 void CreateALGraph(ALGraph *Gp) { cin >> Gp->vexnum >> Gp->arcnum; for (int i = 1; i <= Gp->vexnum; i++) //初始化頂點信息 { Gp->vertices[i].date = i; Gp->vertices[i].into = 0; Gp->vertices[i].firstarc = NULL; } for (int i = 0; i < Gp->arcnum; i++) { int vi, vj, w; cin >> vi >> vj >> w; ArcNode *arc = new ArcNode; arc->adjvex = vj; arc->weight = w; arc->nextarc = Gp->vertices[vi].firstarc; Gp->vertices[vi].firstarc = arc; Gp->vertices[vj].into++; } } bool topo(ALGraph G) { queue<int>que; int sum = 0, flag[MAXN]; //flag用來標記已經輸出的頂點 memset(flag, 0, sizeof(flag)); for (int i = 1; i <= G.vexnum; i++) //把入度為0的頂點入棧 if (G.vertices[i].into == 0){ que.push(i); flag[i] = 1; } while (!que.empty()){ int temp = que.front(); //cout << temp << endl; sum++; que.pop(); change[sum] = temp; ArcNode *pos = G.vertices[temp].firstarc; while (pos != NULL){ G.vertices[pos->adjvex].into--; pos = pos->nextarc; } for (int i = 1; i <= G.vexnum; i++) //把入度為0的頂點入棧 if (G.vertices[i].into == 0 && !flag[i]){ que.push(i); flag[i] = 1; } } return sum == G.vexnum ? true : false; } void CriticalPath(ALGraph G) { int ve[MAXN], vl[MAXN]; //************************ // 以下是求最早發生時間 //************************ for (int i = 1; i <= G.vexnum; i++) ve[i] = 0; for (int i = 1; i <= G.vexnum; i++) { ArcNode *pos = G.vertices[change[i]].firstarc; while (pos != NULL){ int temp = pos->adjvex; if (ve[change[i]] + pos->weight > ve[temp]) ve[temp] = ve[change[i]] + pos->weight; pos = pos->nextarc; } } //*********************** //以下是求最遲發生時間 //*********************** for (int i = 1; i <= G.vexnum; i++) vl[i] = ve[change[G.vexnum]]; cout << ve[change[G.vexnum]] << endl; for (int i = G.vexnum; i >=1 ; i--) { ArcNode *pos = G.vertices[change[i]].firstarc; while (pos != NULL){ int temp = pos->adjvex; if (vl[temp] - pos->weight < vl[change[i]]) vl[change[i]] = vl[temp] - pos->weight; pos = pos->nextarc; } } //****************************** for (int i = 1; i <= G.vexnum; i++) { ArcNode *pos = G.vertices[i].firstarc; while (pos != NULL){ int temp = pos->adjvex; int e = ve[i]; int l = vl[temp] - pos->weight; if (e == l) cout << i << "->" << temp << endl; pos = pos->nextarc; } } } int main() { ALGraph G; CreateALGraph(&G); if (!topo(G)){ cout << "0" << endl; return 0; } CriticalPath(G); return 0; }