#include <iostream> #include <queue> #include <vector> using namespace std; const int maxn=1001; struct edge{ int to; int dis; int waste; edge(int a,int c,int d):to(a), dis(c),waste(d){}; bool operator<(edge y) const{ return dis>y.dis; } }; struct point{ int number; int dis; int waste; point(int a,int b,int c):number(a),dis(b),waste(c){}; bool operator< (point y) const{ if(dis==y.dis) return waste>y.waste; else return dis>y.dis; } }; int dist[maxn]; bool visit[maxn]; int w[maxn]; vector<edge> G[maxn]; priority_queue<point> q; void init(){ for(int i=0;i<maxn;i++) { G[i].clear(); dist[i]=1000; visit[i]=false; w[i]=0; } while(!q.empty()) q.pop(); } int main() { int n,m; while(cin>>n>>m){ if(n==0 && m==0) break; init(); for(int i=0;i<m;i++){ int a,b,d,p; cin>>a>>b>>d>>p; G[a].push_back(edge(b, d, p)); G[b].push_back(edge(a,d,p)); } int start,end; cin>>start>>end; dist[start]=0; q.push(point(start,0,0)); while(!q.empty()){ point tem=q.top(); q.pop(); for(int i=0;i<G[tem.number].size();i++){ edge tp=G[tem.number][i]; if((dist[tp.to]>(dist[tem.number]+tp.dis)) || ( dist[tp.to]==(dist[tem.number]+tp.dis)&& (w[tp.to] >w[tem.number]+tp.waste))){ dist[tp.to]=dist[tem.number]+tp.dis; q.push(point(tp.to,dist[tp.to], tem.waste+tp.waste)); w[tp.to]=w[tem.number]+tp.waste; } } } cout<<dist[end]<<' '<<w[end]<<endl; } }