7-11 key activities (30 points)

Keywords: Algorithm

Title Link

7-11 key activities (30 points)

Suppose an engineering project consists of a group of subtasks, some of which can be executed in parallel, and some must be executed after completing other subtasks. "Task scheduling" includes a group of subtasks and the subtask set on which each subtask can execute.

For example, completing all courses and graduation design of a major can be regarded as a project to be completed by an undergraduate, and each course can be regarded as a sub task. Some courses can be offered at the same time, such as English and C programming, which have no constraints on which course to take first; Some courses can not be offered at the same time, because they have sequential dependencies. For example, C programming and data structure must learn the former first.

However, it should be noted that for A group of subtasks, not any task scheduling is A feasible scheme. For example, in the scheme, "subtask A depends on subtask B, subtask B depends on subtask C, and subtask C depends on subtask A", then none of the three tasks can be executed first, which is an infeasible scheme.

In the task scheduling problem, if the time required to complete each sub task is given, we can calculate the shortest time required to complete the whole project. Among these subtasks, even if some tasks are delayed for several days, the global duration will not be affected; However, some tasks must be completed on time, otherwise the construction period of the whole project will be delayed. This task is called "key activities".

Please write a program to determine whether the task scheduling of a given project is feasible; If the scheduling scheme is feasible, calculate the shortest time required to complete the whole project and output all key activities.

Input format:

Input line 1 gives two positive integers N(≤ 100) and m, where n is the number of task handover points (i.e. nodes connecting two interdependent subtasks, for example, if task 2 is to start after task 1 is completed, there must be a handover point between the two tasks). The handover points are numbered from 1 to N, and M is the number of subtasks, numbered from 1 to M. Then, in line m, three positive integers are given in each line, which are the junction number involved in the start and completion of the task and the time required for the task. The integers are separated by spaces.

Output format:

If task scheduling is not feasible, output 0; Otherwise, the first line outputs the time required to complete the whole project, and the second line starts to output all key activities. Each key activity occupies one line and is output according to the format "V - > W", where V and W are the handover point numbers involved in the start and completion of the task. The sequence rules for the output of key activities are: the smaller the handover point number at the beginning of the task takes precedence. When the starting point number is the same, the sequence of the task is opposite to that at the time of input.

Input example:

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

No blank lines at the end

Output example:

17
1->2
2->4
4->6
6->7

No blank lines at the end

Topology sorting diagram:

To find key activities on the critical path, first start with the node with a penetration of 0,   At the end of the node with an exit of 0, find the earliest start time of each event node in the middle as the element of the early array, so that the maximum value in the last early array is the earliest completion time of the whole project (because each node must be completed before the project can be completed, for those nodes with a degree greater than 1, the slowest activity must be completed before it can start. Therefore, each element in early is the latest generation time of each event.)

Now the earliest completion time of the project is known. Go back backwards to find the latest start time of each event node

 

Code:

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int N = 1010;
struct Edge{
	int to,w;
};
int n,m;
int in[N],out[N],early[N],last[N];
vector<Edge> eg[N],lg[N];
vector<int> sorted;//Storage topology sequence
priority_queue<int,vector<int>,greater<int>> que;
bool TopSorted(){ //Topological sorting
	int cnt = 0;
	for(int i = 1; i <= n; i++){
		if(in[i] == 0){
			que.push(i);
			sorted.push_back(i);
			cnt++;
		}
	}
	while(que.size()){
		int tmp = que.top();
		que.pop();
		for(Edge x:eg[tmp]){
			in[x.to]--;
			if(in[x.to] == 0){
				que.push(x.to);
				sorted.push_back(x.to);
				cnt++;
			}
		}
	}
	if(cnt == n) return true;
	else return false;
}
int main(){
	cin>>n>>m;
	for(int i = 0; i < m; i++){
		int u,v,w;
		cin>>u>>v>>w;
		eg[u].push_back({v,w});
		lg[v].push_back({u,w});
		in[v]++;
		out[u]++;
	}
	if(TopSorted()){
		//Calculate earlyTime (earliest start time)
		int maxx = 0; 
		for(int p:sorted){
			for(Edge tmp:eg[p]){//Find the node pointed to by p and update it
				if(tmp.w + early[p] > early[tmp.to]){
					early[tmp.to] = tmp.w + early[p];
					maxx = max(maxx,early[tmp.to]);
				}
			} 
		}
		cout<<maxx<<endl;
		//Calculate lastTime (latest start time)
		int minn = 0x3f3f3f3f;
		for(int p:sorted){
			last[p] = 0x3f3f3f3f;
			if(out[p] == 0){
				last[p] = maxx;
			}
		}
        //Topology sequence reverse traversal
		for(auto i = sorted.rbegin(); i != sorted.rend(); i++){
			int p = *i;
			for(Edge tmp:lg[p]){//Find the node pointing to p and update it
				if(last[p] - tmp.w < last[tmp.to]){
					last[tmp.to] = last[p] - tmp.w;
				}
			} 
		}
		for(int i = 1; i <= n; i++){//The problem requires that the connection point is small to large
			for(auto it = eg[i].rbegin(); it != eg[i].rend(); it++){//Reverse the order of input
				Edge p = *it;
				if(last[p.to] - p.w == early[i])//Key activities
					printf("%d->%d\n",i,p.to);
			}
		}
	}else {
		cout<<0;
	}
	return 0;
}

Posted by runthis on Fri, 24 Sep 2021 09:22:03 -0700