试题 算法训练 最短路
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。请你计算从1号点到其他点的最短路(顶点从1到n编号)。
输入格式
第一行两个整数n, m。
接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。
输出格式
共n-1行,第i行表示1号点到i+1号点的最短路。
样例输入
3 3
1 2 -1
2 3 -1
3 1 2样例输出
-1
-2数据规模与约定
对于10%的数据,n = 2,m = 2。
对于30%的数据,n <= 5,m <= 10。
对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保证从任意顶点都能到达其他所有顶点。
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
bool vis[20001];
int head[20001],sp[20001];
struct side //创建边变量
{
int u,v,w,former;
}s[200001];
void spfa() //闭环图,用spfa--最短路快速算法
{ //开环图,用 dfs--深度优先
queue<int>q; //创建存储int型变量的队列
q.push(1); //把1推入队列中
vis[1]=1; //1在队列中
while(!q.empty()) //一直循环到队列为空
{
int node=q.front(); //用node寄存队头结点
q.pop(); //将队同结点推出队列
vis[node]=0; //队头结点不在队列中
for(int i=head[node];i!=-1;i=s[i].former) //遍历所有边
{
int v=s[i].v;
int w=s[i].w;
if(sp[node]+w<sp[v])
{
sp[v]=sp[node]+w; //更新v结点的最短路
if(!vis[v]) //v不在队列中
{
q.push(v); //将v推入队列中
vis[v]=1; //v在队列中
}
}
}
}
}
int main()
{
int n,m,i;
cin>>n>>m;
memset(head,-1,sizeof(head)); //给head、vis两个数组赋初值
memset(vis,0,sizeof(vis)); //memset()函数只可赋0,-1两个整型,和所有char型
for(i=0;i<m;i++) //创建边 //c++中int为32b,memset()会把低8b的值复制给高24b,使值出错
{ //如 (1)D=(00000000 00000000 00000000 00000001)B
cin>>s[i].u>>s[i].v>>s[i].w; //赋值后会变为 (00000001 00000001 00000001 00000001)B=(16843009)D
s[i].former=head[s[i].u];
head[s[i].u]=i;
}
for(i=1;i<=n;i++)
sp[i]=99999999; //所有结点的最小路为无穷,便于取最小路
sp[1]=0; //从编号为1的结点开始查找最小路,自己与自己的最小路为0
spfa();
for(i=2;i<=n;i++)
cout<<sp[i]<<endl;
return 0;
}