luoguo P3371 单源最短路径

如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度。
输入输出格式
输入格式:
第一行包含三个整数N、M、S,分别表示点的个数、有向边的个数、出发点的编号。
接下来M行每行包含三个整数Fi、Gi、Wi,分别表示第i条有向边的出发点、目标点和长度。
输出格式:
一行,包含N个用空格分隔的整数,其中第i个整数表示从点S出发到点i的最短路径长度(若S=i则最短路径长度为0,若从点S无法到达点i,则最短路径长度为2147483647)


输入输出样例
输入样例#1: 
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
输出样例#1: 
0 2 4 3


说明
时空限制:1000ms,128M
数据规模:
对于20%的数据:N<=5,M<=15
对于40%的数据:N<=100,M<=10000
对于70%的数据:N<=1000,M<=100000
对于100%的数据:N<=10000,M<=500000


此题目可以用数据结构教材中的Dijkstra算法求解,但是需要注意如下几点:
(1) 如果定义为int型,min+edge[pt].distance会溢出,所以定义成long long型
(2) 如果用二维数组存边,在求路径时计算量太大,超时。
(3) 用链表是比较适合的方法。但是图中有多重边,如果每次插入边时都找是否每条边是否为多重边,也会超时。

(4) 把所有边插入,不管是否为多重边。此时需要注意的是在给D[]赋初始值时,要选取多重边里的最短的一条边。

//注:程序在dev-c++ 下运行

#include <cstdio>
#define INFINITY 0x7FFFFFFF
#define N 10010

struct edgeType
{
int zhongdian;
long long distance;
int next;
}edge[500100];
long long edgeCursor;
long long graph[N];
long long final[N];
long long D[N];
long long i,j,v,w;
long long n,m,s;
long long min;
long long F,G,W;

void ShortestPath(long long v0)
{ 
for(v=1;v<=n;++v)
{ 
final[v]=0;     
D[v]=INFINITY;
}
long long pt;
for(pt=graph[v0];pt!=0;pt=edge[pt].next)
if(edge[pt].distance<D[edge[pt].zhongdian])
D[edge[pt].zhongdian]=edge[pt].distance;

D[v0]=0;    
final[v0]=1; 
for(i=1;i<n;++i)  
{ 
min=INFINITY; 
for(w=1;w<=n;++w)
if(!final[w] && D[w]<min) 
{   
v=w; 
min=D[w];  
} 
if(min<INFINITY)
{
final[v]=1; 
for(pt=graph[v];pt!=0;pt=edge[pt].next)
{
if(!final[edge[pt].zhongdian] && (min+edge[pt].distance<D[edge[pt].zhongdian]))
D[edge[pt].zhongdian]=min+edge[pt].distance;   
}
}
}        
}

int main()
{
scanf("%d%d%d",&n,&m,&s);
for(i=0;i<=n;i++)
graph[i]=0;
for(i=0;i<m;i++)
{
scanf("%d%d%d",&F,&G,&W);
if(F!=G)
{
edge[++edgeCursor].next=graph[F];
edge[edgeCursor].zhongdian=G;
edge[edgeCursor].distance=W;
graph[F]=edgeCursor;
}
}
ShortestPath(s);
for(i=1;i<=n;i++)
printf("%d ",D[i]);
return 0;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值