中国大学MOOC-陈越、何钦铭-数据结构-2018秋——关键活动

版权声明:我的GitHub:https://github.com/617076674。真诚求星! https://blog.csdn.net/qq_41231926/article/details/84674374

我的中国大学MOOC-陈越、何钦铭-数据结构-2018秋代码仓:https://github.com/617076674/MOOC-DataStructure-2018-Autumn

题目描述:

知识点:关键路径

思路:对边取相反数,用SPFA算法求关键路径

题目要求的是所有关键活动。也就是说,如果有两条长度相同关键路径,其上面的活动都应该被罗列出来,但不能罗列相同的路径。活动的罗列顺序不是活动进行的顺序,而是根据题目的最后一句话——“任务开始的交接点编号小者优先,起点编号相同时,与输入时任务的顺序相反”。

为了快速定位该活动的输入顺序,我们用一个二维数组inputSequence[][]存储各边对应的输入顺序。inputSequence[i][j]表示从i到j的有向边的输入顺序。

为了找到起点,我们还需要统计每一个点的入度,其中入度为0的点才可能是起点。

对所有入度为0的点,我们都以其为起点做SPFA算法,取其到其他点的最小距离,如果该最小距离比当前记录的最小距离还要小,我们就需要清空保存结果边信息的resultActivities,将当前路径所经过的边加入resultActivities。如果该最小距离与当前记录的最小距离相等,我们不需要清空resultActivities,直接把当前路径所经过的边加入resultActivities即可。

dfs寻找当前路径所经过的边时,为了防止向resultActivities重复添加边。我们还需要一个visited[]数组来标记某条边是否已被加入resultActivities,visited[i] == true,说明输入顺序为i的那条边已经被加入了resultActivities,visited[i] == false,说明输入顺序为i的那条边还没有加入resultActivities。

时间复杂度主要来源于多次SPFA算法,一次SPFA算法的时间复杂度是O(kM)。空间复杂度是O(N ^ 2)。

C++代码:

扫描二维码关注公众号,回复: 4373554 查看本文章
#include<iostream>
#include<vector>
#include<queue>
#include<set>
#include<algorithm>

using namespace std;

struct node {
	int v;
	int len;
	node(int _v, int _len) {
		v = _v;
		len = _len;
	}
};

struct activity {
	int startV, endV;
	activity(int _startV, int _endV) {
		startV = _startV;
		endV = _endV;
	}
};

int N, M, inDegree[101], d[101], INF = 1000000000, countInq[101], resultMinTime = INF, startPoint;
vector<node> graph[101];	//邻接表形式存储图 
bool inq[101];
vector<int> tempPath;
set<int> pre[101];
int inputSequence[101][101];	//记录每条边输入时的顺序
vector<activity> resultActivities;	//保存关键路径上的边信息 

void init();
bool spfa(int s);
void dfs(int nowVisit, bool visited[]);
bool cmp(activity a1, activity a2);

int main() {
	scanf("%d %d", &N, &M);	//读取节点数和边数 
	bool visited[M];	//标记第i条边是否已经在结果集里 
	fill(inDegree + 1, inDegree + N + 1, 0);
	int v1, v2, len;
	for(int i = 0; i < M; i++) {
		scanf("%d %d %d", &v1, &v2, &len);
		graph[v1].push_back(node(v2, -len));
		inDegree[v2]++;
		inputSequence[v1][v2] = i;
	}
	for(int i = 1; i <= N; i++) {
		if(inDegree[i] == 0) {	//入度为0的点是起点
			init();
			startPoint = i;	//以点i为起点
			bool flag = spfa(startPoint);	//计算点i到其余点的最短路径
			if(flag) {
				int minTime = INF;
				for(int j = 1; j <= N; j++) {
					if(j != i && d[j] < minTime) {	//寻找从点i到其余点的最短路径中的最小值
						minTime = d[j];	//更新最小时间信息
					}
				}
				if(minTime < resultMinTime) {	//如果以i为起点到其余点的最短路径的最小值比当前的最小路径还要小
					resultMinTime = minTime;	//更新最小路径信息
					resultActivities.clear();	//清空resultActivities
					fill(visited, visited + M, false);	//标记所有节点未被访问 
					for(int j = 1; j <= N; j++) {
						if(j != i && d[j] == minTime) {
							dfs(j, visited);
						}
					}
				} else if(minTime == resultMinTime) {
					for(int j = 1; j <= N; j++) {
						if(j != i && d[j] == minTime) {
							dfs(j, visited);
						}
					}
				}
			}
		}
	}
	if(resultMinTime == INF) {
		printf("0\n");
		return 0;
	}
	printf("%d\n", -resultMinTime);	//输出关键路径长度 
	sort(resultActivities.begin(), resultActivities.end(), cmp);	//对结果边进行排序 
	for(int i = 0; i < resultActivities.size(); i++) {	//输出结果 
		printf("%d->%d\n", resultActivities[i].startV, resultActivities[i].endV);
	}
	return 0;
}

void init() {
	fill(d + 1, d + N + 1, INF);
	fill(inq + 1, inq + N + 1, false);
	fill(countInq + 1, countInq + N + 1, 0);
	for(int j = 1; j <= N; j++) {
		pre[j].clear();
	}
}

bool spfa(int s) {
	d[s] = 0;
	queue<int> q;
	q.push(s);
	inq[s] = true;
	countInq[s]++;
	while(!q.empty()) {
		int u = q.front();
		q.pop();
		inq[u] = false;
		for(int i = 0; i < graph[u].size(); i++) {
			int v = graph[u][i].v;
			int len = graph[u][i].len;
			if(d[u] + len < d[v]) {
				d[v] = d[u] + len;
				pre[v].clear();
				pre[v].insert(u);
				if(!inq[v]) {
					q.push(v);
					inq[v] = true;
					countInq[v]++;
					if(countInq[v] > N - 1) {
						return false;
					}
				}
			} else if(d[u] + len == d[v]) {
				pre[v].insert(u);
				if(!inq[v]) {
					q.push(v);
					inq[v] = true;
					countInq[v]++;
					if(countInq[v] > N - 1) {
						return false;
					}
				}
			}
		}
	}
	return true;
}

void dfs(int nowVisit, bool visited[]) {
	tempPath.push_back(nowVisit);
	if(nowVisit == startPoint) {
		for(int i = tempPath.size() - 1; i > 0; i--) {
			int inputNumber = inputSequence[tempPath[i]][tempPath[i - 1]];
			if(!visited[inputNumber]) {
				resultActivities.push_back(activity(tempPath[i], tempPath[i - 1]));
				visited[inputNumber] = true;
			}
		}
		tempPath.pop_back();
		return;
	}
	for(set<int>::iterator it = pre[nowVisit].begin(); it != pre[nowVisit].end(); it++) {
		dfs(*it, visited);
	}
	tempPath.pop_back();
}

bool cmp(activity a1, activity a2) {
	if(a1.startV == a2.startV) {
		return inputSequence[a1.startV][a1.endV] > inputSequence[a2.startV][a2.endV];
	} else {
		return a1.startV < a2.startV;
	}
}

C++解题报告:

猜你喜欢

转载自blog.csdn.net/qq_41231926/article/details/84674374