题目链接
题目分析:
结点编号 0 ~ N-1
题目满足最优子结构,可以直接得出最佳最短路径;也可以先保存所有最短路径,最后统一筛选!
思路一:
直接在遍历Dijkstra()过程中选出最佳最短路径
/**********************************
*@ID: 3stone
*@ACM: PAT.A1030 Travle Plan
*@Time: 18/8/21
*@IDE: VSCode 2018 + clang++
***********************************/
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 505;
const int INF = 0x7fffffff;
int N, M, S, D;
int G[maxn][maxn]; //图
int d[maxn]; //最短距离
int cost[maxn][maxn]; //边的权重
int c[maxn]; //到每个点的最小花费
bool vis[maxn]; //标记是够访问
int pre[maxn]; //记录前驱结点
void Dijkstra(int s) {
//初始化起点
c[s] = 0; d[s] = 0;
for(int i = 0; i < N; i++) { //遍历n次,每次取一个点
//选择最近点
int u = -1, MIN = INF;
for(int j = 0; j < N; j++) {
if(vis[j] == false && d[j] < MIN) {
u = j;
MIN = d[j];
}
}
if(u == -1) return;
vis[u] = true;
//更新最短距离 & 花费
for(int v = 0; v < N; v++) {
if(vis[v] == false && G[u][v] != INF) {
if(d[u] + G[u][v] < d[v]){
d[v] = d[u] + G[u][v];
c[v] = c[u] + cost[u][v]; //更新花费
pre[v] = u;
} else if(d[u] + G[u][v] == d[v] && c[u] + cost[u][v] < c[v]) {
c[v] = c[u] + cost[u][v];
pre[v] = u;
}
}
}//for - v
}//for - i
}//Dijkstra
void dfs_route(int ed) {
if(ed == S){
printf("%d ", S);
return;
}
dfs_route(pre[ed]);
printf("%d ", ed);
}
int main() {
int c1, c2, route_dis, route_cost;
while(scanf("%d%d%d%d", &N, &M, &S, &D) != EOF) {
//初始化
fill(G[0], G[0] + maxn * maxn, INF);
fill(cost[0], cost[0] + maxn * maxn, INF);
fill(vis, vis + maxn, false);
fill(d, d + maxn, INF);
//输入路径信息
for(int i = 0; i < M; i++) {
scanf("%d%d%d%d", &c1, &c2, &route_dis, &route_cost);
G[c1][c2] = route_dis;
G[c2][c1] = route_dis;
cost[c1][c2] = route_cost;
cost[c2][c1] = route_cost;
}
Dijkstra(S);
dfs_route(D);
printf("%d %d\n", d[D], c[D]);
}//while
return 0;
}
思路二:
保存所有最短路径,最后统一筛选!
/**********************************
*@ID: 3stone
*@ACM: PAT.A1030 Travle Plan
*@Time: 18/8/21
*@IDE: VSCode 2018 + clang++
***********************************/
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 505;
const int INF = 0x7fffffff;
int N, M, S, D;
int G[maxn][maxn]; //图
int d[maxn]; //最短距离
int cost[maxn][maxn]; //边的权重
bool vis[maxn]; //标记是够访问
vector<int> pre[maxn]; //记录前驱结点
void Dijkstra(int s) {
//初始化起点
d[s] = 0;
for(int i = 0; i < N; i++) { //遍历n次,每次取一个点
//选择最近点
int u = -1, MIN = INF;
for(int j = 0; j < N; j++) {
if(vis[j] == false && d[j] < MIN) {
u = j;
MIN = d[j];
}
}
if(u == -1) return;
vis[u] = true;
//更新最短距离 & 花费
for(int v = 0; v < N; v++) {
if(vis[v] == false && G[u][v] != INF) {
if(d[u] + G[u][v] < d[v]){
d[v] = d[u] + G[u][v];
pre[v].clear();
pre[v].push_back(u);
} else if(d[u] + G[u][v] == d[v]) {
pre[v].push_back(u);
}
}
}//for - v
}//for - i
}//Dijkstra
vector<int> best_route; //最佳最短路径
int min_cost; // 最小花费
void dfs_route(int ed, vector<int> cur_route, int cur_cost) {
if(ed == S) {
if(cur_cost < min_cost){
best_route = cur_route;
min_cost = cur_cost;
}
}
for(int i = 0; i < pre[ed].size(); i++) {
int pre_node = pre[ed][i];
cur_route.push_back(pre_node);
//也可以每步不累加价值,直到回溯至起点时,在枚举路径(不满足最优子结构的只能这样啦!)
dfs_route(pre_node, cur_route, cur_cost + cost[ed][pre_node]);
cur_route.pop_back();
}
}
int main() {
int c1, c2, route_dis, route_cost;
while(scanf("%d%d%d%d", &N, &M, &S, &D) != EOF) {
//初始化
fill(G[0], G[0] + maxn * maxn, INF);
fill(cost[0], cost[0] + maxn * maxn, INF);
fill(vis, vis + maxn, false);
fill(d, d + maxn, INF);
//输入路径信息
for(int i = 0; i < M; i++) {
scanf("%d%d%d%d", &c1, &c2, &route_dis, &route_cost);
G[c1][c2] = route_dis;
G[c2][c1] = route_dis;
cost[c1][c2] = route_cost;
cost[c2][c1] = route_cost;
}
Dijkstra(S);
vector<int> cur_route;
cur_route.push_back(D);
min_cost = INF;
dfs_route(D, cur_route, 0);
for(int i = best_route.size() - 1; i >= 0; i--) {
printf("%d ", best_route[i]);
}
printf("%d %d\n", d[D], min_cost);
}//while
return 0;
}