#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n,m,s,d;
int e[510][510],dis[510],cost[510][510];
vector<int>pre[510];
bool visit[510];
const int inf = 99999999;
vector<int> path, temppath;
int mincost = inf;
void dfs(int v){ //从终点通过每个结点的pre数组遍历到起点
temppath.push_back(v);
if(v==s){ //遍历到最后,计算选择cost最小的路径
int tempcost=0;
for(int i=temppath.size()-1;i>0;i--){
int id=temppath[i],nextid=temppath[i-1];
tempcost+=cost[id][nextid];
}
if(tempcost<mincost){ //更新代价最小路径
mincost=tempcost;
path=temppath;
}
temppath.pop_back();
return;
}
for(int i=0;i<pre[v].size();i++)
dfs(pre[v][i]);
temppath.pop_back(); //通过v点的路径遍历不到s时逐层递归弹出当前访问的结点v
}
int main() {
fill(e[0], e[0] + 510 * 510, inf);
fill(dis, dis + 510, inf);
scanf("%d%d%d%d", &n, &m, &s, &d);
for(int i=0;i<m;i++){
int a,b;
cin>>a>>b;
scanf("%d",&e[a][b]); //e[a][b]为a b之间dis
e[b][a]=e[a][b];
scanf("%d",&cost[a][b]);
cost[b][a]=cost[a][b];
}
pre[s].push_back(s);
dis[s]=0;
//Dijksta,每次循环 1.寻找当前起点到各点的路径中最短dis[u] 2.更新可能通过u到各点的最短路径
for(int i=0;i<n;i++){ //Dijksta记录路径pre数组,每次确定一个点的最短路径,包括自身循环n次
int u=-1,minn=inf;
for(int j = 0; j < n; j++) {
if(visit[j] == false && dis[j] < minn) { //遍历当前结点到未确定路径各点的dis[j]中最短距离,其中到u结点距离最短
u = j;
minn = dis[j];
}
}
if(u == -1) break;
visit[u] = true; //该点的最短路径已确定
for(int v=0;v<n;v++){ //更新起点通过u点到各点的当前最短距离,第一次循环即更新起点到各点的距离
if(visit[v]==false&&e[u][v]!=inf){
if(dis[v]>dis[u]+e[u][v]){ //经过u点到达v点的距离有无更近
dis[v]=dis[u]+e[u][v];
pre[v].clear(); //若更新路径,清空原来的路径来源,v的最短路径中前一个结点数组压入u结点
pre[v].push_back(u);
}else if(dis[v]==dis[u]+e[u][v]){ //最短路径不唯一
pre[v].push_back(u);
}
}
}
}
dfs(d);
for(int i=path.size()-1;i>=0;i--)
cout<<path[i]<<" ";
cout<<dis[d]<<" "<<mincost;
system("pause");
return 0;
}
PAT 1030 Travel Plan (30 分) Dijksta+DFS求cost最小
于 2022-02-15 08:10:13 首次发布