《算法笔记》P385
考点:Dijkstra、DFS、递归
//方法一:Dijkstra ,pre数组记录最短路径
//c数组记录花费
#include<bits/stdc++.h>
using namespace std;
const int maxn=510;
const int INF=1000000000;
int n,m,st,ed;
bool visit[maxn]={false};
int G[maxn][maxn],d[maxn],c[maxn],cost[maxn][maxn],pre[maxn];
void Dijkstra(int s){
fill(d,d+maxn,INF);
fill(c,c+maxn,INF);
for(int i=0;i<n;i++) pre[i]=i;
d[s]=0;
c[s]=0;
for(int i=0;i<n;i++){
int u=-1,min=INF;
for(int v=0;v<n;v++){
if(visit[v]==false&&d[v]<min){
u=v;
min=d[v];
}
}
if(u==-1) return;
visit[u]=true;
for(int v=0;v<n;v++){
if(visit[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]){
if(c[u]+cost[u][v]<c[v]){
c[v]=c[u]+cost[u][v];
pre[v]=u;
}
}
}
}
}
}
//输出路径
void DFS(int s){
if(s==st){
printf("%d ",s);
return ;
}
DFS(pre[s]);
printf("%d ",s);
}
int main(){
freopen("in.txt","r",stdin);
scanf("%d%d%d%d",&n,&m,&st,&ed);
fill(G[0],G[0]+maxn*maxn,INF);
int u,v;
for(int i=0;i<m;i++){
scanf("%d%d",&u,&v);
scanf("%d%d",&G[u][v],&cost[u][v]);
G[v][u]=G[u][v];
cost[v][u]=cost[u][v];
}
Dijkstra(st);
DFS(ed);
printf("%d %d\n",d[ed],c[ed]);
}
//方法二:pre[v]容器记录所有以v为终点的距离一样短的
//最短路径上,v的所有前驱
//以树形结构遍历每一条从根到叶子的 路径,得到minCost和
//最短path
#include<bits/stdc++.h>
using namespace std;
const int maxn=510;
const int INF=1000000000;
int n,m,st,ed;
bool visit[maxn]={false};
int G[maxn][maxn],d[maxn],cost[maxn][maxn];
int minCost=INF;
vector<int> pre[maxn];
vector<int> tempPath,path;
void Dijkstra(int s){
fill(d,d+maxn,INF);
// fill(c,c+maxn,INF);
// for(int i=0;i<n;i++) pre[i]=i;
d[s]=0;
// c[s]=0;
for(int i=0;i<n;i++){
int u=-1,min=INF;
for(int v=0;v<n;v++){
if(visit[v]==false&&d[v]<min){
u=v;
min=d[v];
}
}
if(u==-1) return;
visit[u]=true;
for(int v=0;v<n;v++){
if(visit[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].clear();
pre[v].push_back(u);
} else if(d[u]+G[u][v]==d[v]){
// if(c[u]+cost[u][v]<c[v]){
// c[v]=c[u]+cost[u][v];
pre[v].push_back(u);
// }
}
}
}
}
}
//输出路径
void DFS(int s){
if(s==st){
//如果访问到了根
tempPath.push_back(s);
int tempCost=0;
for(int i=tempPath.size()-1;i>0;i--){
int id=tempPath[i],idNext=tempPath[i-1];
tempCost+=cost[id][idNext];
}
if(tempCost<minCost){
minCost=tempCost;
path=tempPath;
}
tempPath.pop_back();
return ;
}
//没有访问到叶子,则将这个点加入路径中
tempPath.push_back(s);
for(int i=0;i<pre[s].size();i++){
DFS(pre[s][i]);
}
tempPath.pop_back();
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d%d%d",&n,&m,&st,&ed);
fill(G[0],G[0]+maxn*maxn,INF);
//添加cost的初始化
fill(cost[0],cost[0]+maxn*maxn,INF);
int u,v;
for(int i=0;i<m;i++){
scanf("%d%d",&u,&v);
scanf("%d%d",&G[u][v],&cost[u][v]);
G[v][u]=G[u][v];
cost[v][u]=cost[u][v];
}
Dijkstra(st);
DFS(ed);
for(int i=path.size()-1;i>=0;i--){
printf("%d ",path[i]);
}
printf("%d %d\n",d[ed],minCost);
}