数据结构与算法题目集7-35——城市间紧急救援

我的数据结构与算法题目集代码仓:https://github.com/617076674/Data-structure-and-algorithm-topic-set

原题链接:https://pintia.cn/problem-sets/15/problems/862

题目描述:

数据结构与算法题目集7-35——城市间紧急救援

知识点:带权图的最短路径

思路:SPFA算法+深度优先遍历(回溯)

本题是PAT-ADVANCED1003——Emergency的中文版。

期望时间复杂度是O(kM),其中k是一个常数,在很多情况下k不超过2,可见这个算法异常高效,并且经常性地优于堆优化的Dijkstra算法。

C++代码:

#include<iostream>
#include<queue>
#include<vector>
#include<set>

using namespace std;

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

int N, M, S, D, INF = 1000000000;
int teams[500], d[500], countInq[500];
vector<node> graph[500];
bool inq[500];
set<int> pre[500];
vector<int> tempPath, path;
int count = 0, maxTeams = 0;

bool spfa(int s);
void dfs(int nowVisit);

int main() {
	std::ios::sync_with_stdio(false);
	cin >> N >> M >> S >> D;
	for(int i = 0; i < N; i++) {
		cin >> teams[i];
	}
	for(int i = 0; i < M; i++) {
		int v1, v2, len;
		cin >> v1 >> v2 >> len;
		graph[v1].push_back(node(v2, len));
		graph[v2].push_back(node(v1, len));
	}
	spfa(S);
	dfs(D);
	cout << count << " " << maxTeams << endl;
	for(int i = path.size() - 1; i >= 0; i--){
		cout << path[i];
		if(i == 0){
			cout << endl; 
		}else{
			cout << " ";
		}
	}
	return 0;
}

bool spfa(int s) {
	fill(d, d + N, INF);
	fill(countInq, countInq + N, 0);
	fill(inq, inq + N, false);
	d[s] = 0;
	queue<int> q;
	q.push(s);
	countInq[s]++;
	inq[s] = true;
	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) {
	tempPath.push_back(nowVisit);
	if(nowVisit == S){
		count++;
		int tempTeams = 0;
		for(int i = 0; i < tempPath.size(); i++){
			tempTeams += teams[tempPath[i]];
		}
		if(tempTeams > maxTeams){
			maxTeams = tempTeams;
			path = tempPath;
		}
		tempPath.pop_back();
		return; 
	}
	for(set<int>::iterator it = pre[nowVisit].begin(); it != pre[nowVisit].end(); it++){
		dfs(*it);
	}
	tempPath.pop_back();
}

C++解题报告:

数据结构与算法题目集7-35——城市间紧急救援