-
5 23 5 4 1 2 708 2 3 112 3 4 721 4 5 339 5 4 960 1 5 849 2 5 98 1 4 99 2 4 25 2 1 200 3 1 146 3 2 106 1 4 860 4 1 795 5 4 479 5 4 280 3 4 341 1 4 622 4 2 362 2 3 415 4 1 904 2 1 716 2 5 575
样例输出
-
123
在hiho上看到这道题,大学期间也学到过Dijkstra最短路径算法,但当时没学好,今天花了1个多小时重新看了一下,总算看明白,开心。
另外Dijkstra老爷子还是很不错的,前几天去笔试让写知道的计算机界有贡献的人,想了半天只写出图灵诺依曼,惭愧。
这里有一篇关于Dijkstra算法的文章,还有动图,推荐一下:
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html
下面是我给出的算法的描述(感觉虽然没将算法原理讲清,但是便于实现):
1.初始化将起始点加入到S集合(默认其余的元素在U集合),选择起始点并设置dist[i],dist[i]表示i点到起始点的距离。
2.将U集合中点逐“1”加入到S集合中,加入规则:谁距离起始点最近谁加入S集合(mindist)。加入后更新dist数组重新设置各点到起始点距离。(eg:A为起始点且在S集合,B,C...在U集合,若AB=2(minA*),AC=无穷...BC=3,将B加入到S集合中后,由于AC>AB+BC,所以update dist[iC] = 5,对于U中其它元素同理)
3.重复步骤2直到S集合满。dist即最终结果集。
代码实现:
//dijkstra Ëã·¨Çó×î¶Ì·ÎÊÌâ //Ë㷨˵Ã÷£º /* 1.³õʼ»¯£¬Ñ¡¶¨³õʼµã²¢½«³õʼµã´æÈëS¼¯ºÏÖУ» 2.½«U¼¯ºÏÖеĵãÖð 1 ¼ÓÈëÖÁS¼¯ºÏÖУ¬¼ÓÈë¹æÔò£ºËµ½Æðʼµã¾àÀë×î½ü¾Í½«Ë¼ÓÈ룬¼ÓÈëºóÖØмÆÁ¿U¼¯ºÏÖеĵ㵽ÆðʼµãµÄ¾àÀ룻 (È磺³õʼµãΪA£¬¼¯ºÏSÖе±Ç°Ö»´æÔÚA£¬¼¯ºÏUÖÐÓÐB,CÈô¸É¸öµã£¬AB£¨A*ÖÐ×îСµÄ£©=2£¬AC=ÎÞÇBC=3£¬¸ù¾Ý¹æÔòBµã¼ÓÈ뼯ºÏSºó£¬ÓÉÓÚAC>AB+BC, ËùÒÔAC±»ÖØÖÃΪ5) 3.Öظ´¶þ£¬Ö±µ½È«²¿µã±»¼ÓÈëµ½S¼¯ºÏΪֹ£» add:¹Ø¼üÊý¾Ý½á¹¹£¬Í¼µÄ¼Ç¼¶þάÊý×émap Ç°Çý¼Ç¼һλÊý×éprev ¾àÀë¼Ç¼һάÊý×édist s¼¯ºÏ±êʶÊý×ésMem s¼¯ºÏÊý¾ÝÊýÁ¿ */ #include<stdio.h> long map[1002][1002] ; //map[i][j]¼Ç¼iµ½jµãµÄ¾àÀë long dist[1002] ; //dist[i]¼Ç¼iµ½ÔµãµÄ×î¶Ì¾àÀë int sMem[1002]; //ÈôÔªËØiÔÚ¼¯ºÏSÖУ¬ÔòsMem[i] = 1; ·ñÔòsMem = 0 int sNum; //¼¯ºÏSÖÐÔªËصÄÊýÁ¿ long Dijkstra( int v0,int v1,int N ) ; int main() { int N , M , S , T ; int i , j , k ; long l ; scanf( "%d %d %d %d" , &N,&M,&S,&T ) ; for( i=1;i<=N;i++ ) { for( j=1;j<=N;j++ ) { if(i==j) map[i][j] = 0 ; else map[i][j] = 100000000 ; } } i = 1 ; while( i<=M ) { i++ ; scanf("%d %d %ld",&j,&k,&l) ; if( map[j][k] > l ) map[j][k] = l ; if( map[k][j] > l ) map[k][j] = l ; } printf("%ld\n",Dijkstra( S,T,N )) ; system("pause") ; return 0 ; }//int main() long Dijkstra( int v0,int v1,int N ) { int i ; int j ; long mindist ; int target ; /*for( i=1 ; i<= 100 ; i++ ) { prev[i] = -1 ; } prev[v0] = 0 ;//³õʼ»¯Ç°Çý½ÚµãÊý×é */ for( i=1;i<=N;i++ ) { sMem[i] = 0 ; } sMem[v0] = 1 ; //³õʼ»¯¼Ç¼¼¯ºÏS sNum = 1 ;//³õʼ»¯¼¯ºÏSÊýÁ¿ for( i=1 ;i<=N; i++ ) { dist[i] = map[v0][i] ; } while(sNum<N) { mindist = 100000001 ; for( i=1;i<=N;i++ ) { if( (!(sMem[i])) && dist[i] < mindist ) { target = i ; //iµãÊÇU¼¯ºÏÖоàÀëÔµã×î½üµÄµã mindist = dist[i] ; } } sMem[target] = 1 ; sNum++ ; for( i=1 ; i<=N ; i++ ) { if((!(sMem[i])) && (dist[i]>dist[target]+map[target][i]) ) dist[i] = dist[target]+map[target][i] ; } } return dist[v1] ; }//long Dijkstra( int v0,int v1,int N )
描述
万圣节的早上,小Hi和小Ho在经历了一个小时的争论后,终于决定了如何度过这样有意义的一天——他们决定去闯鬼屋!
在鬼屋门口排上了若干小时的队伍之后,刚刚进入鬼屋的小Hi和小Ho都颇饥饿,于是他们决定利用进门前领到的地图,找到一条通往终点的最短路径。
鬼屋中一共有N个地点,分别编号为1..N,这N个地点之间互相有一些道路连通,两个地点之间可能有多条道路连通,但是并不存在一条两端都是同一个地点的道路。那么小Hi和小Ho至少要走多少路程才能够走出鬼屋去吃东西呢?
输入
每个测试点(输入文件)有且仅有一组测试数据。
在一组测试数据中:
第1行为4个整数N、M、S、T,分别表示鬼屋中地点的个数和道路的条数,入口(也是一个地点)的编号,出口(同样也是一个地点)的编号。
接下来的M行,每行描述一条道路:其中的第i行为三个整数u_i, v_i, length_i,表明在编号为u_i的地点和编号为v_i的地点之间有一条长度为length_i的道路。
对于100%的数据,满足N<=10^3,M<=10^4, 1 <= length_i <= 10^3, 1 <= S, T <= N, 且S不等于T。
对于100%的数据,满足小Hi和小Ho总是有办法从入口通过地图上标注出来的道路到达出口。
输出
对于每组测试数据,输出一个整数Ans,表示那么小Hi和小Ho为了走出鬼屋至少要走的路程。
样例输入