杭电 hdu 2544 最短路 (最短路径 + Dijkstra算法)

杭电  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条商店到赛场的路线。
 

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
UESTC 6th Programming Contest Online
 

Recommend
lcy   |   We have carefully selected several similar problems for you:   2066  1874  1217  2112  1142 







题意:这道题是一道中文题,题意很好理解,就不解释了




题解:我用的是Dijkstra算法,在存放点与点直接的关系时,使用的是静态邻接表,通过hand[]来存放每个点的连接点的头地址,再从后面连接下去,
形成类似链表形式的邻接表。将每条边存放在edge[]结构体数组中,用下表当作他们的地址,存放在hand[]中。
edge[]存放边,
其中有from,表示从这个点开始
to表示到这个地点
在Dijkstra算法中,为了使找到最小的值,采用了优先队列priority_queueq;
在dis[]中,不断更新每个下标代表的地点所采取的最短路径




Dijkstra有缺点,只能有一个源头开始,查找到其它地方的最短路径,起点始终固定,要是要求其它起点,就要从新算。
还有,就是在路径中,不能有负的值,一旦负的值,很有可能会使后面的一片全部出错





#include 
#include 
#include 
#include 
#include 
#include 
#include 

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_queueq;

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;
}


你可能感兴趣的:(最短路径,杭电)