Problem Description
Because of the GFW (Great Firewall), we cannot directly visit many websites, such as Facebook, Twitter, YouTube, etc. But with the help of proxy and proxy server, we can easily get to these website.
You have a list of several proxy servers, some of them can be connected directly but others can’t. But you can visit proxy servers through other proxy server by a one-way connection.
As we all know, the lag of internet visit will decide our feelings of the visit. You have a very smart proxy software which will find the least lag way to reach the website once you choose a directly reachable proxy server.
You know the lag of every connection. The lag of your visit is the all the lags in your whole connection. You want to minimize the lag of visit, which proxy server you will choose?
Input
The first line of each test case is two integers N (0 <= N <= 1000), M (0 <= M <= 20000). N is the number of proxy servers (labeled from 1 to N).
0 is the label of your computer and (N+1) is the label of the server of target website.
Then M lines follows, each line contains three integers u, v, w (0 <= u, v <= N + 1, 1 <= w <= 1000), means u can directly connect to v and the lag is w.
Output
If there are multiple choices, you should output the proxy server with the least label. If you can’t visit the target website by any means, output “-1” (without quotes). If you can directly visit the website and the lag is the least, output “0” (without quotes).
Example Input
4 3 6 0 1 10 1 2 1 2 4 4 0 3 2 3 2 1 3 4 7 2 4 0 2 10 0 1 5 1 2 4 2 1 7 1 3 0 2 1 0 1 2 1 2 1 1 3 0 2 10 0 1 2 1 2 1
Example Output
3 -1 0 1
#include <iostream>
#include<cstdio>
#include<queue>
#define maxn 1005
#define maxm 20005
using namespace std;
/*
注意:
1.用邻接表来存储,用队列来维护
2.每次仅对最短路估计值发生变化了的顶点的所有出边执行松弛操作
*/
struct Node
{
int n;
int first;
}dis[maxn];
int main()
{
int T;
scanf("%d",&T);
int n,m,i,k;
//u、v、w数组大小要根据实际情况来设置,要比m的最大值大1;
int u[maxm],v[maxm],w[maxm];
//first要比n的最大值大1,next要比m的最大值大1;
int first[maxn],next[maxm];
int book[maxn]={0};//book数组用来记录哪些队列已经在队列中;
queue<int> que;
int inf=99999999;
//顶点个数:n,边的条数m;
while(T--)
{
scanf("%d%d",&n,&m);
n=n+1;
//初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
for(i=0;i<=n;i++)
{
dis[i].n=inf;
dis[i].first=inf;
}
dis[0].n=0;
dis[0].first=0;
//初始化book数组,初始均为0,刚开始都不在队列中;
for(i=0;i<=n;i++)
book[i]=0;
//初始化frist数组下标1~n均为-1,表示1~n顶点暂时都没有边;
for(i=0;i<=n;i++)
first[i]=-1;
for(i=0;i<m;i++)
{
//读入每一条边
scanf("%d%d%d",&u[i],&v[i],&w[i]);
//下面两句是建立邻接表的关键
if(u[i]==0)
{
dis[v[i]].first=v[i];
}
next[i]=first[u[i]];
first[u[i]]=i;
}
//1号顶点入队
que.push(0);
book[0]=1;//标记1号顶点已经入队
while(!que.empty())//队列不为空的时候循环
{
k=first[que.front()];//当前需要处理的队首指针
while(k!=-1)//扫描当前顶点所有的边
{
if(dis[v[k]].n>dis[u[k]].n+w[k])//判断是否松弛成功
{
if(dis[u[k]].first!=0)
dis[v[k]].first=dis[u[k]].first;
dis[v[k]].n=dis[u[k]].n+w[k];//更新顶点1到v[k]的路程
//这的book数组用来判断v[k]是否在队列中
//如果不适用一个数组来标记的话,判断一个顶点是否在队列中
//每次都需要从队列的head到tail扫描一遍,很浪费时间
if(book[v[k]]==0)//0表示不在队列中,将顶点v[k]加入队列
{
que.push(v[k]);
book[v[k]]=1;//同时标记v[k]已经入队
}
}else if(dis[v[k]].n==dis[u[k]].n+w[k])
{
if(dis[u[k]].first!=0&&dis[u[k]].first<dis[v[k]].first)
dis[v[k]].first=dis[u[k]].first;
}
k=next[k];
}
//出队
book[que.front()]=0;
que.pop();
}
//输出1号顶点到其余各个顶点的最短路径
if(dis[n].first==inf)
printf("-1\n");
else if(dis[n].first==n)
printf("0\n");
else
printf("%d\n",dis[n].first);
}
return 0;
}