#include <stdio.h>
#include <vector>
#include <queue>
using namespace std;
struct Edge{ //边的信息
int u;
int v;
int weight;
int cost;
Edge( int u1 ,int v1 ,int weight1 ,int cost1)
{
u = u1;
v = v1;
weight = weight1;
cost = cost1;
}
};
vector<Edge> graph[1001]; //邻接表存储无向图的边,便于访问起始和终止顶点及其权值
struct PQueueNode{ //队列结点
int u ; //顶点编号
int distance; //从起始顶点到u顶点的距离
PQueueNode(int u1 , int distance1)
{
u = u1;
distance = distance1;
}
};
bool operator < (PQueueNode lhs , PQueueNode rhs)
{
return lhs.distance > rhs.distance; //按距离进行降序排序构造小根堆!
}
int Cost[1001]; //起点到顶点i的费用
int Dijksstra( int s ,int t) //起始顶点+终止顶点
{
//定义一个优先队列
priority_queue<PQueueNode> pqueue;
int distance[1001]; //从起始顶点到i顶点的距离
bool isVisited[1001]; //记录某个顶点是否已经访问过
for(int i = 0 ; i < 1001 ; i++) //初始化距离和是否访问
{
distance[i] = -1; //初始均为-1 表示无穷均不可达
isVisited[i] = false; //初始每个顶点均未访问
Cost[i] = 0; //费用初始化0
}
distance[s] = 0; //起始点到自己距离为0
PQueueNode node( s,0); //建立一个队列结点作为队首结点
pqueue.push(node); //将第一个结点入队
while ( !pqueue.empty() ) //优先队列不为空时
{
int u = pqueue.top().u; // 将当前队首结点的编号存起来
pqueue.pop(); //队头出队
//遍历u编号顶点的对应的边邻接表
for( int i = 0 ; i < graph[u].size() ;i++)//遍历u号顶点的所有邻接边取出终止顶点
{
int v = graph[u][i].v; //将u到其他邻居的编号存起来
int weight = graph[u][i].weight; //u->v的的权值(距离)
int cost = graph[u][i].cost; //u->v的费用
if( distance[v] == -1 //起点->v的距离如果为无穷 则只能先到u再到v
|| distance[v] > distance[u]+weight //起点到v的距离大于起点到u再到v的距离
//起点到v和起点先到u再到v的距离一致且 起点到v的费用大于起点到u再到v的费用时
//也可以更新费用为最小
|| (distance[v] == distance[u]+weight && Cost[v] > Cost[u]+cost )
)
{
distance[v] = distance[u] + weight; //更新距离起点到u再到v
//将v顶点压入优先队列 继续执行
//距离大费用就大,距离大的时候也要更新起点到v的距离为较小值
Cost[v] = Cost[u] + cost; //更新起点到v的最小费用
PQueueNode next(v,distance[v]); //创建队列结点
pqueue.push(next);
}
}
}//处理完整个图了从起点到其他顶点的最短距离均完成
return distance[t] ; //返回s->t的最短距离
}
int main()
{
int n,m;
while (scanf("%d%d",&n,&m) != EOF)
{
if(n==0 && m==0)
{
break;
}
for(int i = 0 ; i <= n ;i++) //每组测试完成后重新清空一下1-n编号(0号舍弃)的边邻接表
{
graph[i].clear();
}
for(int i = 0 ; i < m ;i++)
{
//注意是无向图(迪杰斯特拉)
int u,v,weight,cost; //顶点1,2对应权值(距离),费用
scanf("%d%d%d%d",&u,&v,&weight,&cost);
Edge e1(u,v,weight,cost);
graph[u].push_back(e1);
Edge e2(v,u,weight,cost);
graph[v].push_back(e2);
}
int s,t;
scanf("%d%d",&s,&t);
int d = Dijksstra(s,t); //先执行迪杰斯特拉获取到最短距离及对应的最小费用
int c = Cost[t]; //最小费用存在全局数组中 ,迪杰斯特拉只能返回一个值
printf("%d %d\n", d,c);
}
return 0;
}