/*
Dijkstra 算法求单源最短路径
将所有结点分为两个集合 S D ,S为未访问的结点集合,D为已访问的集合
每次从集合D中找到一条到达集合S中结点的最短路径,将该点加入到D集合,并更新加入该点后的最短路径
*/
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int MAX=1E9;
const int Size=720;
class Dist{ //存放找到的当前最短路径
public:
int index; //结点下标
int length; //路径长度
int pre; //当前结点前驱下标
friend const bool operator < (const Dist &a,const Dist &b)
{
return a.length>b.length;//小的优先级高,用于优先队列
}
};
class Graph{
public:
int numv; //结点数
int *mark; //标记已访问结点,未访问为0
int * *ma; //邻接矩阵
Graph(int n)
{
numv=n;
ma=(int * *)new int [n];
for(int i=0;i<n;i++)ma[i]=new int[n];
mark=new int [n];
}
};
void Dijkstra(Graph &G,int s,Dist* &D) //s为源点
{
using std::priority_queue;
D=new Dist[G.numv];
for(int i=0;i<G.numv;i++) //Dist初始化
{
G.mark[i]=0;
D[i].index=i;
D[i].length=MAX; //Dist存放长度为极大值,若算法结束后仍为极大值认为未找到可达路径
D[i].pre=s;
}
D[s].length=0;
priority_queue<Dist> H; //优先队列,存放最短路径
H.push(D[s]);
for(int i=0;i<G.numv;i++)
{
bool f=false;
Dist d;
while(!H.empty())
{
d=H.top();
H.pop();
if(G.mark[d.index]==0) //寻找未访问结点
{
f=true;
break;
}
}
if(!f)break; //未找到可访问结点退出
int v=d.index; //v找到的当前结点
G.mark[v]=1; //标记v为已访问
for(int i=0;i<G.numv;i++)
{
if(G.ma[v][i]>0) //访问v的边,i为目标点
{
if(D[i].length>(D[v].length+G.ma[v][i])) //若经过v的某条边,使得s到i的距离比Dist中存放的最短路更短
{
D[i].length=D[v].length+G.ma[v][i]; //更新Dist[i](s到i的最短路)
D[i].pre=v; //改变到i的最短路前驱为v
H.push(D[i]); //将新的最短路放入优先队列
}
}
}
}
}
int main()
{
int n;cout <<"d"<<endl;
int a,b,c,e;
Dist *d;
Graph g(100);
while(cin>>n)
{
g.numv=n+1;
for(int i=0;i<=n;i++)g.mark[i]=0;
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
g.ma[i][j]=0;
while(cin>>a>>b)
{
if(a==-1&&b==-1)break;
cin >> c;
g.ma[a][b]=c;
}
cin>>e;
Dijkstra(g,e,d);
for(int i=1;i<n+1;i++)
cout << d[i].index << " " <<d[i].length <<" "<<d[i].pre<<endl;
}
return 0;
}
/*
3
1 2 8
1 3 3
3 2 3
-1 -1
1
5
1 4 30
1 2 10
1 5 100
2 3 50
3 5 10
4 5 60
4 2 10
4 3 20
-1 -1
1
6
1 3 15
2 1 10
2 4 2
2 6 30
4 2 20
4 5 15
5 2 4
6 3 4
6 5 10
6 1 10
-1 -1
2
*/