//http://ac.jobdu.com/problem.php?cid=1040&pid=76
#include <stdio.h>
#include <vector>
using namespace std;
struct E //邻接表中链表元素结构体(边)
{
int next; //直接相邻节点
int c; //该边权值
int cost;
};
vector <E> edge[1001]; //vector作邻接链表,结点不超过100
bool mark[1001]; //mark[i]为true时,表示结点i的最短路径长度已经得到,结点i加入集合k
int cost[1001];
int dis[1001]; //mark[i]=true时,从1到i的最短路径长度
//mark[i]=false时,从1到k中某点的最短路径长度再加上从该点到i的距离
int main()
{
int n,m,i,j;
int S,T; //起点,终点
while (scanf("%d%d",&n,&m)!=EOF && n!=0 &&m!=0)
{
for (i=1;i<=n;i++)
{
edge[i].clear(); //初始化邻接链表
}
while (m--) //根据输入边信息,建立邻接表
{
int a,b,c,cost;
scanf("%d%d%d%d",&a,&b,&c,&cost);
E tmp; //新建节点
tmp.c=c;
tmp.cost=cost;
tmp.next=b;
edge[a].push_back(tmp); //将该边加入结点a的边表,作为邻接边
tmp.next=a;
edge[b].push_back(tmp); //加入结点b的边表(因为无向图所以加两次)
}
scanf("%d%d",&S,&T);
for (i=1;i<=n;i++) //初始化
{
dis[i]=-1; //-1表示不可达
mark[i]=false; //所有节点不属于集合k
}
dis[S]=0;
mark[S]=true; //长度为0,s标志的起点加入集合k
int newP=S;
for (i=1;i<n;i++) // 循环n-1次,按路径递增顺序确定其他点的最短路径
{
for (j=0;j<edge[newP].size();j++) //遍历新加入k的结点的直接相邻边
{
int t=edge[newP][j].next; //该边的另一节点
int c=edge[newP][j].c;
int co=edge[newP][j].cost;
if (mark[t]==true) //另一节点也属于k,跳过
{
continue;
}
if (dis[t]==-1 || dis[t]>dis[newP]+c ||(dis[t]==dis[newP]+c && cost[t]>cost[newP]+co ))
{ //不可达, 更短距离, 相同距离下花费更少
dis[t]=dis[newP]+c;
cost[t]=cost[newP]+co;
}
}
int min=123123123; //最小值初始化为一个大数
for (j=1;j<=n;j++) //遍历所有节点
{
if (mark[j]==true) //若其属于结合k,跳过
{
continue;
}
if (dis[j]==-1) //若该节点仍不可达(肯定不最短),跳过
{
continue;
}
if (dis[j]<min) //依次比较找最短
{
min=dis[j]; //暂时保存最短
newP=j; //暂时保存newP最短边的另一结点
}
}
mark[newP]=true; // 该点加入集合k,dis[newP]表示从1到newP的最短距离
}
printf("%d %d\n",dis[T],cost[T]);
}
return 0;
}
/*
注意判定条件:距离相同时,再比较选择花费较少的
*/