昨天下午的热身赛D题---《旅游啦》,刚开始以为是要先求单源最短路径,于是呼呼啦啦把DJ的算法搬出来实现,完了后才发现不需要这么做,题目其实是想考察图的最优代价深度优先搜索,无奈最后卡在了回溯时的代价求和。
那道题以后再去A掉,现在先写这个最短路径,关于图的各种应用算法,考研时也要求掌握,不过离上机实现还差一点,Dj的算法实际就是贪心在图论中的应用,使用final[i]记录编号为i的结点此时是否和源点在同一集合中,使用dist[i]记录从源点到i结点的当前最短路径长度,不过这道题另外增加了路径花费,于是把dist封装成结构体,这无关技术,不必赘述,用pre[i]记录寻找到i结点时的前置结点,可根据该数组顺藤摸瓜,最终构造出整条路径,这道题只要求求dist值,所以pre数组可以省略。
算法刚开始时,将final[s](s为源点)置为1,其余结点的final值置为0,将dist[i]的值初始化为e[s][i],不相连的话以-1代替,因为不知道OJ上int的最大值,以-1更保险。初始化完成,在dist中寻找满足以下两个条件的结点j:1.final[j] == 0; 2. dist[j]值最小。这个点即为该轮循环找到的最佳跳点,并入集合中,即final[j]置为1,以j结点为跳点,更新dist数组中所有未并入集合中的结点,如果dist[i] > dist[j] + e[j][i](当然前提是j需要与i直接连通), 则将dist[i]更新为dist[j] + e[j][i]。循环上述"跳点--更新dist--更新跳点"的过程,直至需要寻找的终点t并入集合中,算法结束,直接输出dist[t]即可AC。
以下是代码,内存开大是为了方便操作,用动态分配内存的方法可以压缩掉多余的开销:
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 typedef struct{
5 int d;
6 int p;
7 }edge;
8
9 edge e[1000][1000];
10 int final[1000];//该点是否和源点属于同一集合
11 edge dist[1000];//记录从源点到其他个各顶点当前最短路径长度和最小花费
12
13 int main()
14 {
15 long n,m;
16 int temp1,temp2,temp3,temp4;
17 long i,j;
18 int s,t;
19 int minlength,minprice,templength,tempprice;
20 int jump;//跳点
21 while(scanf("%ld %ld",&n,&m) != EOF && (n != 0 || m != 0))
22 {
23 for(i =0; i < n; i ++)
24 {
25 for(j = 0; j < n; j ++)
26 {
27 e[i][j].d = -1;
28 e[i][j].p = -1;
29 }
30 }
31 for(i = 0; i < n; i ++)
32 {
33 final[i] = 0;
34 }
35 for(i = 0; i < m; i ++)
36 {
37 scanf("%d %d %d %d",&temp1,&temp2,&temp3,&temp4);
38 e[temp1 - 1][temp2 - 1].d = temp3;
39 e[temp1 - 1][temp2 - 1].p = temp4;
40 e[temp2 - 1][temp1 - 1].d = temp3;
41 e[temp2 - 1][temp1 - 1].p = temp4;
42 }
43 scanf("%d %d",&s,&t);
44 final[s - 1] = 1;
45 for(i = 0; i < n; i ++)
46 {
47 dist[i].d = e[s - 1][i].d;
48 dist[i].p = e[s - 1][i].p;
49 }
50 jump = s - 1;
51 while(final[t - 1] != 1)//t结点未并入集合中
52 {
53 for(i = 0; i < n; i ++)
54 {
55 if(final[i] != 1)
56 {
57 minlength = dist[i].d;
58 minprice = dist[i].p;
59 if(jump != s - 1)
60 {
61 if(e[jump][i].d != -1)
62 {
63 templength = dist[jump].d + e[jump][i].d;
64 tempprice = dist[jump].p + e[jump][i].p;
65 if(templength != -1)
66 {
67 if(minlength == -1 || (minlength > templength) || (minlength == templength && minprice > tempprice))
68 {
69 minlength = templength;
70 minprice = tempprice;
71 }
72 }
73 }
74 }
75 dist[i].d = minlength;
76 dist[i].p = minprice;
77 }
78 }
79
80 temp1 = dist[0].d;
81 temp2 = dist[0].p;
82 temp3 = 0;
83 for(i = 1; i < n; i ++)
84 {
85 if(dist[i].d == -1 || final[i] == 1)
86 {
87 continue;
88 }
89 else if(final[temp3] == 1 || temp1 == -1 || dist[i].d < temp1 || (dist[i].d == temp1 && dist[i].p < temp2))
90 {
91 temp1 = dist[i].d;
92 temp2 = dist[i].p;
93 temp3 = i;
94 }
95 }
96 final[temp3] = 1;
97 jump = temp3;
98 }
99 printf("%d %d\n",dist[t - 1].d, dist[t - 1].p);
100 }
101 return 0;
102 }
103 /**************************************************************
104 Problem: 1008
105 User: qiushuiruyan
106 Language: C
107 Result: Accepted
108 Time:20 ms
109 Memory:8732 kb
110 ****************************************************************/
多说一下:关于最短路径问题,有SPFA算法更加有效,而且,该算法是由西南交通大学段凡丁于1994年发表的,有空去学习学习^_^