jdoj 1008 最短路径问题 代码及分析
这是在一个叫做九度的OJ上面的题,这是一个典型的最短路问题。题目很简单,就只有一个要注意的地方,就是路径有可能是重复的,要把这种情况考虑进去。我就是为此WA了好几次,最后只好参考那里的BBS,才知道原来这题是要检测重复路径的。改了以后就立刻AC了!
这题是我第一次用Dij算法做的题,因为以前都只会Floyd算法,用在这里后就TLE了一次,因为这里有1000个点,如果用Floyd的话,O(n^3)在就是最少10^9次运算了。后来想起了Dij的算法,然后根据我印象中对Dij算法的思路,打了我第一个Dij算法的代码。
下面是我的代码,也是像其他题解一样,在旁边有注解的。如果觉得有什么不明白,或者有更好的优化方法,欢迎留言~
View Code
1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4 #define MAX 9999999999999999 //刚开始不停的WA,我以为是int不够大,所以直接用了long long
5
6 typedef struct arc //这是用来储存弧信息的结构体的定义
7 {
8 int end;
9 long long dis;
10 long long cost;
11 struct arc *next;
12 }Arc;
13
14 Arc *begin[1005]; //起点相同的弧放在一起,顺序查找
15 long long dis[1005]; //这是从起点到各个点的距离
16 long long cost[1005]; //从起点到各个点的花费
17 int visited[1005]; //点是否确定了
18
19 int findmin(int n) //找出与起点的距离最小的那一点,返回点的标号
20 {
21 int i;
22 long long min=MAX;
23 int num=0;
24
25 for(i=1; i<=n; i++)
26 if(!visited[i]&&min>dis[i])min=dis[i], num=i; //如果是确定了的点就不要重复返回了
27 return num;
28 }
29
30 int main()
31 {
32 int i;
33 int n, m;
34 int a, b;
35 long long c, d; //cost,distance
36 Arc *p, *tmp;
37
38 while(scanf("%d%d", &n, &m)&&(n||m))
39 {
40 memset(begin, 0, sizeof(begin));
41 memset(visited, 0, sizeof(visited));
42
43 for(i=1; i<=1003; i++)
44 cost[i]=dis[i]=MAX;
45 while(m--)
46 {
47 scanf("%d%d%lld%lld", &a, &b, &d, &c); //因为这是无向图所以两个方向都要设置
48 tmp=(Arc *)malloc(sizeof(Arc));
49 tmp->next=begin[a];
50 tmp->end=b;
51 tmp->dis=d;
52 tmp->cost=c;
53 begin[a]=tmp;
54 tmp=(Arc *)malloc(sizeof(Arc));
55 tmp->next=begin[b];
56 tmp->end=a;
57 tmp->dis=d;
58 tmp->cost=c;
59 begin[b]=tmp;
60 }
61
62 scanf("%d%d", &a, &b);
63 c=d=MAX; //额……突然发现这是多余的
64 visited[a]=1;
65 p=begin[a];
66 dis[a]=cost[a]=0;
67 while(p) //把各点信息放进dis和cost数组,因为可能有重复的路径,所以这里也是要比较大小的
68 {
69 if(dis[p->end]>dis[a]+p->dis)
70 dis[p->end]=dis[a]+p->dis,
71 cost[p->end]=cost[a]+p->cost;
72 else if(dis[p->end]==dis[a]+p->dis&&cost[p->end]>cost[a]+p->cost)
73 cost[p->end]=cost[a]+p->cost;
74 p=p->next;
75 }
76 while(i=findmin(n))
77 {
78 visited[i]=1;
79 p=begin[i];
80 while(p)
81 {
82 if(dis[p->end]>dis[i]+p->dis)
83 dis[p->end]=dis[i]+p->dis,
84 cost[p->end]=cost[i]+p->cost;
85 else if(dis[p->end]==dis[i]+p->dis&&cost[p->end]>cost[i]+p->cost)
86 cost[p->end]=cost[i]+p->cost;
87 p=p->next;
88 }
89 }
90 printf("%lld %lld\n", dis[b], cost[b]);
91 }
92
93 return 0;
94 }
2 #include<string.h>
3 #include<stdlib.h>
4 #define MAX 9999999999999999 //刚开始不停的WA,我以为是int不够大,所以直接用了long long
5
6 typedef struct arc //这是用来储存弧信息的结构体的定义
7 {
8 int end;
9 long long dis;
10 long long cost;
11 struct arc *next;
12 }Arc;
13
14 Arc *begin[1005]; //起点相同的弧放在一起,顺序查找
15 long long dis[1005]; //这是从起点到各个点的距离
16 long long cost[1005]; //从起点到各个点的花费
17 int visited[1005]; //点是否确定了
18
19 int findmin(int n) //找出与起点的距离最小的那一点,返回点的标号
20 {
21 int i;
22 long long min=MAX;
23 int num=0;
24
25 for(i=1; i<=n; i++)
26 if(!visited[i]&&min>dis[i])min=dis[i], num=i; //如果是确定了的点就不要重复返回了
27 return num;
28 }
29
30 int main()
31 {
32 int i;
33 int n, m;
34 int a, b;
35 long long c, d; //cost,distance
36 Arc *p, *tmp;
37
38 while(scanf("%d%d", &n, &m)&&(n||m))
39 {
40 memset(begin, 0, sizeof(begin));
41 memset(visited, 0, sizeof(visited));
42
43 for(i=1; i<=1003; i++)
44 cost[i]=dis[i]=MAX;
45 while(m--)
46 {
47 scanf("%d%d%lld%lld", &a, &b, &d, &c); //因为这是无向图所以两个方向都要设置
48 tmp=(Arc *)malloc(sizeof(Arc));
49 tmp->next=begin[a];
50 tmp->end=b;
51 tmp->dis=d;
52 tmp->cost=c;
53 begin[a]=tmp;
54 tmp=(Arc *)malloc(sizeof(Arc));
55 tmp->next=begin[b];
56 tmp->end=a;
57 tmp->dis=d;
58 tmp->cost=c;
59 begin[b]=tmp;
60 }
61
62 scanf("%d%d", &a, &b);
63 c=d=MAX; //额……突然发现这是多余的
64 visited[a]=1;
65 p=begin[a];
66 dis[a]=cost[a]=0;
67 while(p) //把各点信息放进dis和cost数组,因为可能有重复的路径,所以这里也是要比较大小的
68 {
69 if(dis[p->end]>dis[a]+p->dis)
70 dis[p->end]=dis[a]+p->dis,
71 cost[p->end]=cost[a]+p->cost;
72 else if(dis[p->end]==dis[a]+p->dis&&cost[p->end]>cost[a]+p->cost)
73 cost[p->end]=cost[a]+p->cost;
74 p=p->next;
75 }
76 while(i=findmin(n))
77 {
78 visited[i]=1;
79 p=begin[i];
80 while(p)
81 {
82 if(dis[p->end]>dis[i]+p->dis)
83 dis[p->end]=dis[i]+p->dis,
84 cost[p->end]=cost[i]+p->cost;
85 else if(dis[p->end]==dis[i]+p->dis&&cost[p->end]>cost[i]+p->cost)
86 cost[p->end]=cost[i]+p->cost;
87 p=p->next;
88 }
89 }
90 printf("%lld %lld\n", dis[b], cost[b]);
91 }
92
93 return 0;
94 }
Dij算法还是得多点用,否则到真的比赛的时候就会浪费太多时间了!
written by Lyon
beta 1:
可以在上面代码的第77和78行之间加上
if(i==b)break;
这样的目的是找到最小路以后直接跳出,做到剪枝优化的效果。因为根据dij算法的分析,之后找到的到达终点的路径长度只会比最小路径更长,不会再次相等。