//第一种:普通Dijkstra写法
#include <iostream>
#include <vector>
#define MAXN 510
#define MAXDATA 510
using namespace std;
int N,M,S,D;
//G:两点之间直接距离,C:两点之间直接花费
int G[MAXN][MAXN];int C[MAXN][MAXN];
int dist[MAXN];int cost[MAXN];
//dist[i]:i到源点距离,G[S][i]:i是否S邻接点
//cost[i]:i到源点花费,C[S][i]:i到S直接花费
int collected[MAXN];
int pre[MAXN];
int FindMin(){
int minValue=MAXDATA,minId=-1;
for(int i=0;i<N;i++){
if(collected[i]==0 && dist[i]<minValue){
minValue=dist[i];
minId=i;
}
}
return minId;
}
void Dijkstra(){
fill(dist,dist+N,MAXDATA);
fill(cost,cost+N,MAXDATA);
fill(pre,pre+N,-1);
dist[S]=0;
cost[S]=0;
while(1){
int minId=FindMin();
if(minId==-1) break;
else{
collected[minId]=1;
for(int i=0;i<N;i++){
if(collected[i]==0 && G[minId][i]!=MAXDATA){
if(dist[i]>dist[minId]+G[minId][i]){
dist[i]=dist[minId]+G[minId][i];
cost[i]=cost[minId]+C[minId][i];
pre[i]=minId;
}else if(dist[i]==dist[minId]+G[minId][i]){
if(cost[i]>cost[minId]+C[minId][i]){
cost[i]=cost[minId]+C[minId][i];
pre[i]=minId;
}
}
}
}
}
}
}
void PrintPath(){
vector<int> path;
int cur=D;
while(cur!=-1){
path.push_back(cur);
cur=pre[cur];
}
for(int i=path.size()-1;i>=0;i--){
printf("%d ",path[i]);
}
}
int main(){
scanf("%d %d %d %d",&N,&M,&S,&D);
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
G[i][j]=MAXDATA;
C[i][j]=MAXDATA;
}
}
int c1,c2,d,cos;
for(int i=0;i<M;i++){
scanf("%d %d %d %d",&c1,&c2,&d,&cos);
G[c1][c2]=d;G[c2][c1]=d;
C[c1][c2]=cos;C[c2][c1]=cos;
}
Dijkstra();
PrintPath();
printf("%d %d",dist[D],cost[D]);
return 0;
}
//第二种:Dijkstra + DFS写法
#include <iostream>
#include <vector>
#define MAXN 510
#define MAXDATA 1000000000
using namespace std;
int N,M,S,D;
//G:两点之间直接距离,C:两点之间直接花费
int G[MAXN][MAXN];int C[MAXN][MAXN];
int dist[MAXN];
//dist[i]:i到源点距离,G[S][i]:i是否S邻接点
int collected[MAXN];
vector<int> pre[MAXN];
int FindMin(){
int minValue=MAXDATA,minId=-1;
for(int i=0;i<N;i++){
if(collected[i]==0 && dist[i]<minValue){
minValue=dist[i];
minId=i;
}
}
return minId;
}
void Dijkstra(){
fill(dist,dist+N,MAXDATA);
dist[S]=0;
while(1){
int minId=FindMin();
if(minId==-1) break;
else{
collected[minId]=1;
for(int i=0;i<N;i++){
if(collected[i]==0 && G[minId][i]!=MAXDATA){
if(dist[i]>dist[minId]+G[minId][i]){
dist[i]=dist[minId]+G[minId][i];
pre[i].clear();
pre[i].push_back(minId);
}else if(dist[i]==dist[minId]+G[minId][i]){
pre[i].push_back(minId);
}
}
}
}
}
}
vector<int> tempPath;
vector<int> Path;
int minCost=MAXDATA,tempCost;
void DFS(int v){
if(v == S){//到达叶子结点(即起点),tempPath存储一条完整路径
//1:push
tempPath.push_back(v);
//2:culculate current cost
tempCost=0;
for(int i=tempPath.size()-1;i>0;i--){
tempCost+=(C[tempPath[i]][tempPath[i-1]]);//cost里存的未必是当前路径的花费
}
if(tempCost<minCost){
minCost=tempCost;
Path=tempPath;//vector重载了=,可以直接赋值
}
//3:pop
tempPath.pop_back();
return;//本条路径结束,递归返回
}
//1:push
tempPath.push_back(v);
//2:递归计算当前结点下的所有路径
for(int i=0;i<pre[v].size();i++){
DFS(pre[v][i]);
}
//3:pop
tempPath.pop_back();
}
int main(){
scanf("%d %d %d %d",&N,&M,&S,&D);
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
G[i][j]=MAXDATA;
C[i][j]=MAXDATA;
}
}
int c1,c2,d,cos;
for(int i=0;i<M;i++){
scanf("%d %d %d %d",&c1,&c2,&d,&cos);
G[c1][c2]=d;G[c2][c1]=d;
C[c1][c2]=cos;C[c2][c1]=cos;
}
Dijkstra();
DFS(D);
for(int i=Path.size()-1;i>=0;i--){
printf("%d ",Path[i]);
}
printf("%d %d",dist[D],minCost);
return 0;
}