//土尔逊Torson 编写于2023/07/07
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
#include <climits>
using namespace std;
const int MAXN = 1001;
const int INF = INT_MAX; //无穷设为很大的数
struct Edge13801 {
int to; //终点
int length; //长度
int price; //花费
Edge13801(int t, int l, int p):to(t),length(l),price(p){}
};
struct Point13801 {
int number; //点的编号
int distance; //源点到该点距离
Point13801(int n,int d):number(n),distance(d){}
bool operator<(const Point13801& p)const {//优先级队列一般是大的值在前通过重载 < 操作符实现 小的值在前
return distance > p.distance; //距离小的优先级高
}
};
vector<Edge13801> graph13801[MAXN]; //邻接表实现的图
int dis13801[MAXN]; //源点到各点距离
int cost13801[MAXN]; //记录花费
void Dijkstra(int s) {
priority_queue<Point13801> myPriorityQueue13801;
dis13801[s] = 0;
cost13801[s] = 0;
myPriorityQueue13801.push(Point13801(s, dis13801[s]));
while (!myPriorityQueue13801.empty()) {
int u = myPriorityQueue13801.top().number;//离源点最近的点
myPriorityQueue13801.pop();
for (int i = 0; i < graph13801[u].size(); ++i) {
int v = graph13801[u][i].to;
int l = graph13801[u][i].length;
int p = graph13801[u][i].price;
if (dis13801[v] == dis13801[u] + l && cost13801[v] > cost13801[u] + p ||
dis13801[v] > dis13801[u] + l) { //注意松弛操作的条件变换
dis13801[v] = dis13801[u] + l;
cost13801[v] = cost13801[u] + p;
myPriorityQueue13801.push(Point13801(v, dis13801[v]));
}
}
}
return;
}
int main() {
int n, m;
while (scanf("%d%d", &n, &m) != EOF) {
if (n == 0 && m == 0) {
break;
}
memset(graph13801, 0, sizeof(graph13801)); //图的初始化
fill(dis13801, dis13801 + n + 1, INF); //距离初始化为无穷
fill(cost13801, cost13801 + n + 1, INF); //花费初始化为无穷
while (m--) {
int from, to, length, price;
scanf("%d%d%d%d", &from, &to, &length, &price);
graph13801[from].push_back(Edge13801(to, length, price));
graph13801[to].push_back(Edge13801(from, length, price));
}
int s, t; //起点与终点
scanf("%d%d", &s, &t);
Dijkstra(s);
printf("%d %d\n", dis13801[t], cost13801[t]);
}
system("pause");
return EXIT_SUCCESS;
}
// 64 位输出请用 printf("%lld")