patA1030

思路:使用dijkstra+DFS的方法。首先要改造pathTo数组,使其每个元素都可以储存多个前驱节点的编号。在松弛节点时,若松弛后的值严格小于原来的disTo值,就要清空pathTo的对应元素,然后加入新的前驱节点编号;否则直接加入即可。
得到pathTo数组后,从汇点开始使用DFS反向向源点进行DFS。每次搜索到源点时,就计算其第二标尺的值。注意:要记得在当前节点处理完毕后将当前节点从vector容器中删除。



代码:

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

using namespace std;

//用于邻接表
struct edge {
	int id;
	int dist;	//距离
	int cost;	//花费
	edge(int x, int y, int z) :id(x), dist(y), cost(z) {}
};

//用于优先队列
struct vertex {
	int id;
	int d;	//节点到源点的当前最短距离
	vertex(int x, int y) :id(x), d(y) {}
};

//优先队列的比较函数
struct cmp {
	bool operator()(vertex& a, vertex& b) {
		return a.d > b.d;
	}
};


const int MAX = 500;
const int INF = 0x3fffffff;
//节点数,边数,源点,汇点
int N, M, S, D;
//邻接表
vector<edge> adj[MAX];
//判别节点是否已找到最短路径
bool visit[MAX] = { false };
//每个节点当前到源点的最短路径长度
int disto[MAX];
//每个节点在最短路径树上的前驱
set<int> pathto[MAX];
//最短路径
int mindist = 0;
//最小花费
int mincost = INF;
//最优路径
vector<int> path;
vector<int> temppath;


//读输入
void input() {
	cin >> N >> M >> S >> D;
	for (int i = 0; i < M; i++) {
		int u, v, d, c;
		cin >> u >> v >> d >> c;
		adj[u].push_back(edge(v, d, c));
		adj[v].push_back(edge(u, d, c));
	}
}


//找最短路径,存到pathto数组中
void dijkstra() {
	//初始化源点的数据
	visit[S] = true;
	disto[S] = 0;

	priority_queue<vertex, vector<vertex>, cmp> pq;
	pq.push(vertex(S, 0));

	while (true) {
		//当前节点u
		vertex u = pq.top();
		pq.pop();
		int uid = u.id;
		visit[uid] = true;
		int udist = u.d;

		//找到汇点,退出
		if (uid == D)
			break;


		//松弛当前节点
		for (int i = 0; i < adj[uid].size(); i++) {
			int v = adj[uid][i].id;
			if (!visit[v]) {
				if (udist + adj[uid][i].dist < disto[v]) {
					//更新disto与pathto
					disto[v] = udist + adj[uid][i].dist;
					pathto[v].clear();
					pathto[v].insert(uid);
				}
				else if (udist + adj[uid][i].dist == disto[v]) {
					pathto[v].insert(uid);
				}
			}
		}

		//构造优先队列
		pq = priority_queue<vertex, vector<vertex>, cmp>();
		for (int i = 0; i < N; i++) {
			if (!visit[i])
				pq.push(vertex(i, disto[i]));
		}
	}

	mindist = disto[D];
}


//计算temppath的花费
int calcost() {
	int tempcost = 0;
	for (int i = 0; i < temppath.size() - 1; i++) {
		int u = temppath[i], v = temppath[i + 1];
		for (int j = 0; j < adj[u].size(); j++) {
			if (adj[u][j].id == v) {
				tempcost += adj[u][j].cost;
				break;
			}
		}
	}
	return tempcost;
}

//对最短路径树,从u开始向源点DFS,计算最少花费
void DFS(int u) {
	//DFS到了源点
	if (u == S) {
		temppath.push_back(u);
		//计算花费
		int tempcost = calcost();

		//更新path
		if (tempcost < mincost) {
			mincost = tempcost;
			path = temppath;
		}

		temppath.pop_back();
	}
	else {
		temppath.push_back(u);
		for (auto iter = pathto[u].begin(); iter != pathto[u].end(); iter++) {
			DFS(*iter);
		}
		temppath.pop_back();	//记得要把最后一个元素弹出
	}
}



int main(void) {
	input();
	fill(disto, disto + MAX, INF);

	dijkstra();
	DFS(D);

	//输出
	for (int i = path.size() - 1; i >= 0; i--) {
		cout << path[i] << " ";
	}
	cout << mindist << " " << mincost;
	return 0;
}
posted @ 2022-04-27 17:50  带带绝缘体  阅读(25)  评论(0)    收藏  举报