HDU 2544 最短路 <SPFA算法>

来源:互联网 发布:美国ge膜和陶氏膜 知乎 编辑:程序博客网 时间:2024/06/01 01:34

最短路

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 43152    Accepted Submission(s): 18950


Problem Description
在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?

 

Input
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。
 

Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间
 

Sample Input
2 11 2 33 31 2 52 3 53 1 20 0
 

Sample Output
32
 

Source
UESTC 6th Programming Contest Online
 
      SPFA不适用于求负环!
      负环是什么?1.在无向图中一个环里面有一个负值就叫负环!(因为1->2和2->1就构成了一个环)
                               2.  在有向图中,首先是一个环,然后环上的边的权值相加之和为负值,就是负环!
  思路:这道题是将起点和终点给你了,然后让你求从起点到终点的最短的距离,因为这道题的每条边的权值都是正的,所以
我们可以用gijkstra算法来做,我们也可以用今天学的SPFA来做,当用SPFA来做的时候,首先我们要会使用邻接矩阵,和队列!
队列:先进先出就是队列!
邻接矩阵:将不同的边进行编号,然后将编号放到head数组里面,然后放在对应的边的指针区,(放在指针区的head的值都是从-1开始的,然后最后一个head的值没有
被放到指针区中,因为head数组的下标是对应边的起点,而head的值是对应起点的边的编号,所以我们在输入起点的编号之后,
我们可以通过起点将对应的于起点相连的边的最大编号找到,然后这条边的所有的信息也就找到了,包括相同起点的边也能够找到
,因为在存储边的时候把边的指针区指向的就是之前存储的相同起点的边的编号,然后再输入相同起点的边的时候,我们就将之前的那个边的
编号赋值给这条边的next变量,也就是让next指向之前的同起点的边,最后head里面的值就是最大的那个以下标为起点的边的编号
,然后当我们遍历边的时候,我们从同起点编号最大的边开始,通过指针,找到第二大的,最终head的值为-1的时候,就遍历完以这个
点为起点的边了,每次都重复这个操作;中间的操作就是一直更新,然后将被更新的下表放进队列里面,然后以这个点为起点,再更新与其相连的
边的另一个顶点的最小值!一直重复这样做,直到所有的值都是最小的为止!)
 
代码:
   
//思路:这道题是将起点和终点给你了,然后让你求从起点到终点的最短的距离,因为这道题的每条边的权值都是正的,所以//我们可以用gijkstra算法来做,我们也可以用今天学的SPFA来做,当用SPFA来做的时候,首先我们要会使用邻接矩阵,和队列!/*队列:先进先出就是队列!邻接矩阵:将不同的边进行编号,然后将编号放到head数组里面,然后放在对应的边的指针区,(放在指针区的head的值都是从-1开始的,然后最后一个head的值没有被放到指针区中,因为head数组的下标是对应边的起点,而head的值是对应起点的边的编号,所以我们在输入起点的编号之后,我们可以通过起点将对应的于起点相连的边的最大编号找到,然后这条边的所有的信息也就找到了,包括相同起点的边也能够找到,因为在存储边的时候把边的指针区指向的就是之前存储的相同起点的边的编号,然后再输入相同起点的边的时候,我们就将之前的那个边的编号赋值给这条边的next变量,也就是让next指向之前的同起点的边,最后head里面的值就是最大的那个以下标为起点的边的编号,然后当我们遍历边的时候,我们从同起点编号最大的边开始,通过指针,找到第二大的,最终head的值为-1的时候,就遍历完以这个点为起点的边了,每次都重复这个操作;中间的操作就是一直更新,然后将被更新的下表放进队列里面,然后以这个点为起点,再更新与其相连的边的另一个顶点的最小值!一直重复这样做,直到所有的值都是最小的为止!) */ #include <stdio.h>#include <string.h>#include <algorithm>#include <queue>#define INF 0x3f3f3f3f//这里面不能用0xfffffff,因为用这个不能用memset来赋值! using namespace std;int n,m;struct Edge{int from, to, val, next;}edge[10005];int edgenum;int dis[105];int vis[105];int head[10005];void init(){edgenum=0;memset(head,-1,sizeof(head));}void addEdge(int u,int v,int w){Edge E={u,v,w,head[u]};//u为起点,v为终点,w为权值,head为同起点的上一条边的编号 edge[edgenum]=E;head[u]=edgenum++;}void getmap(){int a,b,c;for(int i=0;i<m;i++)//以一个点为起点建立邻接表! {scanf("%d%d%d",&a,&b,&c);addEdge(a,b,c);addEdge(b,a,c);}memset(vis,0,sizeof(vis));memset(dis,INF,sizeof(dis));}void SPFA(){queue<int>q;q.push(1);dis[1]=0;vis[1]=1;while(!q.empty()){int u=q.front();q.pop();vis[u]=0;for(int i=head[u];i!=-1;i=edge[i].next)//邻接表!(以一个点为中心来遍历相邻的点!) {int v=edge[i].to;if(dis[v]>dis[u]+edge[i].val)//更新 {dis[v]=dis[u]+edge[i].val;if(vis[v]==0){vis[v]=1;//赋值号! q.push(v);//因为有可能更新的值对其他的点的最短的距离会造成影响,所以要将其放进队列,然后以这个点为起点再将其他的点的最短距离进行更新! }}}}printf("%d\n",dis[n]);}int main(){while(scanf("%d%d",&n,&m)&&(n||m)){init();getmap();SPFA();}}

 
搜索
0 0