杭电 hdu 2544 最短路 (最短路径 + Dijkstra算法)
最短路
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 39824 Accepted Submission(s): 17369
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条商店到赛场的路线。
输入保证至少存在1条商店到赛场的路线。
Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间
Sample Input
2 1 1 2 3 3 3 1 2 5 2 3 5 3 1 2 0 0
Sample Output
3 2
Source
Recommend
题意:这道题是一道中文题,题意很好理解,就不解释了
题解:我用的是Dijkstra算法,在存放点与点直接的关系时,使用的是静态邻接表,通过hand[]来存放每个点的连接点的头地址,再从后面连接下去,
形成类似链表形式的邻接表。将每条边存放在edge[]结构体数组中,用下表当作他们的地址,存放在hand[]中。
edge[]存放边,
其中有from,表示从这个点开始
to表示到这个地点
在Dijkstra算法中,为了使找到最小的值,采用了优先队列priority_queue<node>q;
在dis[]中,不断更新每个下标代表的地点所采取的最短路径
Dijkstra有缺点,只能有一个源头开始,查找到其它地方的最短路径,起点始终固定,要是要求其它起点,就要从新算。
还有,就是在路径中,不能有负的值,一旦负的值,很有可能会使后面的一片全部出错
#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn = 10005;
const int INF = 0x3f3f3f3f; //无穷大
int hand[maxn]; //每个下标表示那个点,而数组里面存的是每个点与其连接的地址的第一个
int dis[maxn]; //存放从初始点到这个下标的最短路径
int path[maxn]; //用来记录每条最短路径的经过
int vist[maxn]; //用来标记这个点是否已经遍历过了0为没有遍历,1为遍历过了
int top; //用来记录edge[]结构体数组中,队头的位置,用来确定空的位置
struct node{
int from;
int valou;
friend bool operator < (node a, node b){ //重载,用来使放进queue中的元素按照路径最短的先输出
return (a.valou > b.valou);
}
};
priority_queue<node>q;
struct fun{ //用来存放每一条边的信息
int from;
int to;
int v;
int next; //在邻接表中用来指向下一个结构体用的
}edge[maxn];
void Add_edge (int from, int to, int v){ //将边放进邻接表中
edge[top].from = from;
edge[top].to = to;
edge[top].v = v;
edge[top].next = hand[from]; //插入到hand[]之后的第一个,就是将后面的地址给新来的,然后将新来的地址给hand[]
hand[from] = top++; //简单的类似链表的插入步骤
}
void Init (int n, int m){ //初始化的过程
int i, from, to, v;
top = 0;
memset (hand, -1, sizeof (hand));
memset (path, -1, sizeof (path));
memset (dis, INF, sizeof (dis)); //先赋值给每个点的距离都是无限大,然后不断求最小的
memset (vist, 0, sizeof (vist)); //使每个点都处在没有访问过的状态
dis[1] = 0;
for (i = 1; i <= m; ++i){ //输入边,将边放进邻接表中
scanf ("%d%d%d", &from, &to, &v);
Add_edge (from, to, v);
Add_edge (to, from, v);
}
}
void Dijkstra (int n){ //Dijkstra算法
node now, next;
int i, from, v;
while (!q.empty()) q.pop(); //清空queue
now.from = 1;
now.valou = 0;
q.push(now); //首先起始点传入到队列中
while (!q.empty()){
now = q.top();
q.pop();
from = now.from;
v = now.valou;
if (vist[from]) continue; //如果这个点访问过了,就跳过
vist[from] = 1;
for (i = hand[from]; i != -1; i = edge[i].next){ //将与最短路径的点相连的点都更新一遍,将dis[]的值都更新
if (vist[edge[i].to]) continue;
if (v + edge[i].v < dis[edge[i].to]){ //要是这个点到和其相连的点的路径比其原先的短,就更新这个dis[]
dis[edge[i].to] = v + edge[i].v;
next.from = edge[i].to;
next.valou = dis[edge[i].to];
q.push(next); //并将这个更新后的点放入queue中
path[edge[i].to] = from;
}
}
}
}
int main(){
int n, m, i;
while (scanf ("%d%d", &n, &m) != EOF){
if (n == 0 && m == 0) break;
Init (n, m);
Dijkstra(n);
printf ("%d\n", dis[n]); //因为起始点是给出的,所以从起始点到各个点的最短路径可以直接输出了
}
return 0;
}