A traveler's map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.
Input Specification:
Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (≤500) is the number of cities (and hence the cities are numbered from 0 to N−1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:
City1 City2 Distance Cost
where the numbers are all integers no more than 500, and are separated by a space.
Output Specification:
For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.
Sample Input:
4 5 0 3 0 1 1 20 1 3 2 30 0 3 4 10 0 2 2 20 2 3 1 20
Sample Output:
0 2 3 3 40
// 解题思路:
// 经典的最短路径算法
// 求出所有的同等最短路径,进行dfs找到花费最少的唯一一条即可
// 这里用的spfa + dfs, 建议没负权都直接用dijkstra,这里心血来潮写了spfa
#include <bits/stdc++.h>
using namespace std;
// 链式前向星存图,其实用邻接表或邻接矩阵即可,同心血来潮。。。
const int maxn = 5e2 + 5;
struct edge
{
int v, dis, next;
}e[maxn * maxn];
int head[maxn], size = 0;
void insert(int &u, int &v, int &cos, int &dis){
e[size] = (edge){v, dis, head[u]};
head[u] = size++;
e[size] = (edge){u, dis, head[v]};
head[v] = size++;
}
// dfs中要直接查询两点之间边的cost, 所以要另外直接存在一个矩阵中
int dis[maxn], ori_cost[maxn][maxn];
vector<int> pre[maxn], temppath;
bool vis[maxn];
// spfa求解最短路
queue<int> q;
void spfa(int s, int d)
{
dis[s] = 0;
vis[s] = true;
q.push(s);
int u;
while(!q.empty()){
u = q.front();
q.pop(), vis[u] = false;
for(int v, i = head[u]; ~i; i = e[i].next){
v = e[i].v;
// 更新最短距离,且将pre路径重置
if ((e[i].dis + dis[u]) < dis[v]){
if(!vis[v]) q.push(v), vis[v] = true;
dis[v] = e[i].dis + dis[u];
pre[v].clear();
pre[v].push_back(u);
}
// 相等则也加入并列路径,用来之后求cost最少路径
else if((e[i].dis + dis[u]) == dis[v]){
pre[v].push_back(u);
}
}
}
}
int n, m, s, d;
// dfs在最短路径中深搜得到最少花费的那条路径,用栈保存
int anscost = 1e8;
stack<int> sta, ans;
void dfs(int v, int tempcost){
sta.push(v);
if(v == s){
if(tempcost < anscost){
anscost = tempcost;
ans = sta;
}
sta.pop();
return;
}
for(int i = 0; i < pre[v].size(); i++){
dfs(pre[v][i], tempcost + ori_cost[v][pre[v][i]]);
}
sta.pop();
}
int main()
{
// 初始化
memset(head, -1, sizeof(head));
memset(dis, 0x3f, sizeof(dis));
// 读入数据
cin >> n >> m >> s >> d;
int u, v, cost, distance;
for(int i = 0; i < m; i++)
{
scanf("%d %d %d %d", &u, &v, &distance, &cost);
insert(u, v, cost, distance);
ori_cost[u][v] = ori_cost[v][u] = cost;
}
spfa(s, d);
dfs(d, 0);
// 输出答案路径 和 结果
while(!ans.empty())
{
printf("%d ", ans.top());
ans.pop();
}
printf("%d %d\n", dis[d], anscost);
return 0;
}
参考了柳婼的题解:https://blog.youkuaiyun.com/liuchuo/article/details/52315580