7-11 關鍵活動(30 分)(拓撲排序與關鍵活動)
拓撲排序與關鍵活動
參考 一道 題目:
7-11 關鍵活動(30 分)
題目 要求
作者: DS課程組
單位: 浙江大學
時間限制: 400ms
記憶體限制: 64MB
程式碼長度限制: 16KB
假定一個工程專案由一組子任務構成,子任務之間有的可以並行執行,有的必須在完成了其它一些子任務後才能執行。“任務排程”包括一組子任務、以及每個子任務可以執行所依賴的子任務集。
比如完成一個專業的所有課程學習和畢業設計可以看成一個本科生要完成的一項工程,各門課程可以看成是子任務。有些課程可以同時開設,比如英語和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
程式碼:
C++
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <vector>
#include <queue>
#include <algorithm>
int **input; //The input order of the activity v -> w, using in the compare function
bool compare(pair<int, int> a, pair<int, int>b)
{
return a.first != b.first ? a.first < b.first : input[a.first][a.second] > input[b.first][b.second];
}
void top_sort(int **time, int *inDegree, int *outDegree, int n)
{
queue<int> q;
int count = 0;
for (int i = 0; i < n; i++)
if (inDegree[i] == 0) {
q.push(i);
count++;
}
int *earliest = new int[n]; //The earliest starting time of each vertex 每個頂點的最早開始時間
fill(earliest, earliest + n, 0);
while (!q.empty()) {
int v = q.front();
q.pop();
for (int w = 0; w < n; w++)
if (time[v][w] != -1) { //An activity of v-> w exists
/* If the earliest starting time of v + time[v][w] larger than the starting time of
w, then w can not start so early. */
if (earliest[v] + time[v][w] > earliest[w]) earliest[w] = earliest[v] + time[v][w];
if (--inDegree[w] == 0) {
q.push(w);
count++;
}
}
}
if (count < n) { //loop exists
cout << 0 << endl;
return;
}
int max = 0;
for (int v = 0; v < n; v++)
if (outDegree[v] == 0 && earliest[v] > max)
max = earliest[v];
cout << max << endl;
vector<pair<int, int>> keyActivies;
int *latest = new int[n]; //The latest ending time of each vertex 每個頂點的最晚結束時間
fill(latest, latest + n, max);
for (int v = 0; v < n; v ++)
if (outDegree[v] == 0)
q.push(v);
while (!q.empty()) {
int v = q.front();
q.pop();
for (int w = 0; w < n; w++)
if (time[w][v] != -1) { //Activity of w -> v exists
/*If the latest ending time of v - time[w][v] smaller than the ending time of
w, then w can not end so late. */
if (latest[v] - time[w][v] < latest[w]) latest[w] = latest[v] - time[w][v];
if (latest[v] - time[w][v] - earliest[w] == 0) keyActivies.push_back({ w, v }); //w->v is a key activity
if (--outDegree[w] == 0)
q.push(w);
}
}
sort(keyActivies.begin(), keyActivies.end(), compare);
for (auto it = keyActivies.begin(); it != keyActivies.end(); it++)
printf("%d->%d\n", it->first + 1, it->second + 1);
}
int main()
{
int n, m;
cin >> n >> m;
//AOE graph 活動在邊上
int *inDegree = new int[n]; //入度
int *outDegree = new int[n]; //出度
int **time = new int*[n]; //The lasting time of the activity v -> w
input = new int*[n]; //The input order of the activity v -> w
for (int i = 0; i < n; i++) {
inDegree[i] = outDegree[i] = 0;
time[i] = new int[n];
input[i] = new int[n];
for (int j = 0; j < n; j++)
time[i][j] = input[i][j] = -1; //Initialize
}
for (int i = 0; i < m; i++) { //Inserts Edge(activities)
int v, w, t;
cin >> v >> w >> t;
v--;
w--;
time[v][w] = t;
input[v][w] = i; //Input order 輸入順序,輸出時需要此順序
inDegree[w]++;
outDegree[v]++;
}
top_sort(time, inDegree, outDegree, n);
return 0;
}
Java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.LinkedList;
import java.util.Queue;
public class KeyActivity {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
StreamTokenizer st = new StreamTokenizer(
new BufferedReader(new InputStreamReader(System.in)));
st.nextToken();
int nCheck = (int) st.nval;//The number of check points
int time[][] = new int[nCheck][nCheck];//The lasting time of an activity between 2 check points
int input[][] = new int[nCheck][nCheck];//The input order of each activity
int inDegree[] = new int[nCheck];
int outDegree[] = new int[nCheck];
init(time, input, inDegree, outDegree);//Initialize arrays
st.nextToken();
int nActivity = (int) st.nval;//The number of activities
for (int i = 0; i < nActivity; i ++) {
st.nextToken();
int x = (int) st.nval - 1;//One of the 2 check points of an activity
st.nextToken();
int y = (int) st.nval - 1;//Another check point of the activity
st.nextToken();
int lastingTime = (int) st.nval;//The lasting time of the activity
time[x][y] = lastingTime;
input[x][y] = i;//The i-th input
inDegree[y] ++;
outDegree[x] ++;//x->y, x out, y in
}
top(time, input, inDegree, outDegree);//find out the key activities
}
/* Initialize the graph and arrays. */
private static void init(int[][] time, int[][] input, int[] inDegree, int[] outDegree) {
// TODO Auto-generated method stub
int nCheck = time.length;
for (int i = 0; i < nCheck; i ++) {
for (int j = 0; j < nCheck; j ++)
time[i][j] = input[i][j] = -1;
inDegree[i] = outDegree[i] = 0;
}
}
/* Top sort, find out the key activities. */
private static void top(int[][] time, int[][] input, int[] inDegree, int[] outDegree) {
// TODO Auto-generated method stub
int nCheck = time.length;//The number of check points
int count = 0;
Queue <Integer> queue = new LinkedList<Integer>();
int earliest[] = new int[nCheck];//The earliest starting time of each check points
for (int v = 0; v < nCheck; v ++) {//v: Vertexes(check points) of the graph
earliest[v] = 0;//Initialize
if (inDegree[v] == 0) {
queue.offer(v);
count ++;
}
}
while (! queue.isEmpty()) {
int v = queue.poll();
for (int w = 0; w < nCheck; w ++)
if (time[v][w] != -1) {//In the graph, v->w has edge
/* If the earliest starting time of v + the time of activity between
* v->w lager than the earliest starting time of w,
* so w can not start so early*/
if (earliest[v] + time[v][w] > earliest[w])
earliest[w] = earliest[v] + time[v][w];
if (--inDegree[w] == 0) {
queue.offer(w);
count ++;
}
}
}//while
if (count < nCheck) {
System.out.println("0");
return ;
}
//else
int max = 0;
for (int v = 0; v < nCheck; v ++) {
if (outDegree[v] == 0) {
queue.offer(v);
if (earliest[v] > max)//Find the maximum earliest starting time of the
max = earliest[v]; //check points with "outDegree" zero
}
}
System.out.println(max);
int latest[] = new int[nCheck];//The latest ending time of each check points
for (int v = 0; v < nCheck; v ++)
latest[v] = max;//Initialize
while (!queue.isEmpty()) {
int v = queue.poll();
for (int w = 0; w < nCheck; w ++) {
if (time[w][v] != -1) {//w->v has edge in the graph
/* If the latest ending time of v - the time of activity between
* w->v smaller than the latest ending time of w,
* then w can not end so late*/
if (latest[v] - time[w][v] < latest[w])
latest[w] = latest[v] - time[w][v];
/* If the latest ending time of v - the earliest starting time of
* w - the time of the activity between w->v greater than 0,
* then w->v is not key activity*/
if (latest[v] - earliest[w] - time[w][v] > 0)
time[w][v] = -1;//w->v is not key activity
if (--outDegree[w] == 0)
queue.offer(w);
}
}
}//while
for (int v = 0; v < nCheck; v ++) {
count = 0;
for (int w = 0; w < nCheck; w ++)
if (time[v][w] != -1)//v->w is key activity
count ++;
if (count == 0)
continue;
int arr[] = new int[count];
count = 0;
for (int w = 0; w < nCheck; w ++)
if (time[v][w] != -1)
arr[count ++] = w;
sort(arr, input, v);
for (int i = 0; i < count; i ++)
System.out.println((v + 1) + "->" + (arr[i] + 1));
}
}
/* Sorts. */
private static void sort(int[] arr, int[][] input, int v) {
// TODO Auto-generated method stub
int si, d;
int sedgewick[] = {41, 19, 5, 1, 0};
int n = arr.length;
for (si = 0; sedgewick[si] >= n; si ++)
;
for (d = sedgewick[si]; d > 0; d = sedgewick[++si]) {
for (int p = d; p < n; p +=d) {
int temp = arr[p];
int i;
for (i = p; i > 0 && input[v][arr[i - d]] < input[v][temp]; i -= d)
arr[i] = arr[i - d];
arr[i] = temp;
}
}
}
}