uva 567(图论) + 图论入门算法分析

这道题的大致意思是给你一个有20个点的无向图,再给你最多100个查询。让你每次查询输出两个顶点之间的最短路径长度。

本题是最基础的图论题,解决方法有多种,下面我们列举若干种方法并结合其效率进行讨论:

一、简单BFS

这种算法是最基本的算法,对于任意两个点直接用广度优先搜索惊醒最短路径求解。写起来方便但是效率并不怎么高。

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 #include <algorithm>
 7 #include <vector>
 8 #include <queue>
 9 #include <stack>
10 #define LEN 30
11 using namespace std;
12 
13 int Map[LEN][LEN], vis[LEN], cnt = 1;
14 
15 typedef struct{
16    int v, step;
17 }P;
18 
19 int BFS(int st, int end)
20 {
21     queue<P> q;
22     P ss;
23     ss.v = st;
24     ss.step = 0;
25     vis[st] = 1;
26     q.push(ss);
27     while(!q.empty()){
28         P vex = q.front();
29         q.pop();
30         if(vex.v==end){
31             return vex.step;
32         }
33         for(int i=1; i<22; i++){
34             P newv;
35             newv.v = i;
36             newv.step = vex.step+1;
37             if(Map[vex.v][i]==1 && vis[i]==0){
38                 vis[i] = 1;
39                 q.push(newv);
40             }
41         }
42     }
43     return -1;
44 }
45 
46 int main()
47 {
48 //    freopen("in.txt", "r", stdin);
49 
50     int vex, n;
51     while(scanf("%d", &n)!=EOF){
52         //building Map
53         memset(Map, 0, sizeof Map);
54         for(int i=0; i<n; i++){
55             scanf("%d", &vex);
56             Map[1][vex] = Map[vex][1] = 1;
57         }
58         for(int i=2; i<20; i++){
59             scanf("%d", &n);
60             for(int j=0; j<n; j++){
61                 scanf("%d", &vex);
62                 Map[i][vex] = Map[vex][i] = 1;
63             }
64         }
65         //Reading Questions ,solve and Output
66         int q, a, b;
67         scanf("%d", &q);
68         printf("Test Set #%d
", cnt++);
69         for(int i=0; i<q; i++){
70             scanf("%d%d", &a, &b);
71             memset(vis, 0, sizeof vis);
72             int ans = BFS(a, b);
73             printf("%2d to %2d: %d
", a, b, ans);
74         }
75         printf("
");
76     }
77     return 0;
78 }
View Code

二、简单BFS+记忆化

上一种算法只要稍稍改进一下即可在时间效率上有不错的提升,首先我们从搜索过程中考虑在广度优先搜索中我们再求到最小值之前其实经过了很多节点,我们每到一个结点其实已经求出了起始点到他的最短路径。若是用一张表记录下来我们下次就可以不重复求解。这次程序中dis数组就起到了这个作用。若询问时dis[a][b]==-1则说明在以前没有求解过,需调用BFS。否则直接输出相应表项即可。

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 #include <algorithm>
 7 #include <vector>
 8 #include <queue>
 9 #include <stack>
10 #define LEN 30
11 
12 using namespace std;
13 
14 int Map[LEN][LEN], vis[LEN], cnt = 1;
15 int dis[LEN][LEN];
16 
17 typedef struct{
18    int v, step;
19 }P;
20 
21 int BFS(int st, int end)
22 {
23     queue<P> q;
24     P ss;
25     ss.v = st;
26     ss.step = 0;
27     vis[st] = 1;
28     q.push(ss);
29     while(!q.empty()){
30         P vex = q.front();
31         q.pop();
32         if(dis[st][vex.v]==-1)dis[st][vex.v] = vex.step;    //做记录
33         if(vex.v==end){
34             return vex.step;
35         }
36         for(int i=1; i<22; i++){
37             P newv;
38             newv.v = i;
39             newv.step = vex.step+1;
40             if(Map[vex.v][i]==1 && vis[i]==0){
41                 vis[i] = 1;
42                 q.push(newv);
43             }
44         }
45     }
46     return -1;
47 }
48 
49 int main()
50 {
51 //    freopen("in.txt", "r", stdin);
52 
53     int vex, n;
54     while(scanf("%d", &n)!=EOF){
55         //building Map
56         memset(Map, 0, sizeof Map);
57         memset(dis, -1, sizeof dis);
58         for(int i=0; i<22; i++) dis[i][i] = 0;
59         for(int i=0; i<n; i++){
60             scanf("%d", &vex);
61             Map[1][vex] = Map[vex][1] = 1;
62         }
63         for(int i=2; i<20; i++){
64             scanf("%d", &n);
65             for(int j=0; j<n; j++){
66                 scanf("%d", &vex);
67                 Map[i][vex] = Map[vex][i] = 1;
68             }
69         }
70         //Reading Questions ,solve and Output
71         int q, a, b;
72         scanf("%d", &q);
73         printf("Test Set #%d
", cnt++);
74         for(int i=0; i<q; i++){
75             scanf("%d%d", &a, &b);
76             memset(vis, 0, sizeof vis);
77             int ans;
78             if(dis[a][b] == -1) {       //如果没有在求解否则输出
79                 ans = BFS(a, b);
80                 dis[a][b] = dis[b][a] = ans;
81             }
82             else ans = dis[a][b];
83             printf("%2d to %2d: %d
", a, b, ans);
84         }
85         printf("
");
86     }
87     return 0;
88 }
View Code

三、dijkstra算法

本题边的权值均为1,用dij算法是大材小用了,但是从时间上看是n^3与前一算法大致一样。我用了n次dij就把任意两点之间的距离都求了出来最后只需查询dis数组即可得到答案。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 #include <algorithm>
 7 #include <vector>
 8 #include <queue>
 9 #include <stack>
10 #define LEN 30
11 #define INF 0x7fffffff
12 using namespace std;
13 
14 int Map[LEN][LEN], dis[LEN][LEN], vis[LEN], cnt = 1;
15 
16 void init()
17 {
18     for(int i=0; i<=20; i++){
19         for(int j=0; j<=20; j++)
20             Map[i][j] = INF;
21         Map[i][i] = 0;
22     }
23     memset(dis, 0, sizeof dis);
24 }
25 
26 void Dijkstra(int vex)
27 {
28     memset(vis, 0, sizeof vis);
29     for(int i=1; i<=20; i++)
30         dis[vex][i] = Map[vex][i];
31     vis[vex] = 1;
32     for(int i=1; i<20 ;i++)
33     {
34         int min, mindis = INF;
35         for(int j=1; j<=20; j++)
36             if(dis[vex][j]<mindis && vis[j] == 0)
37             {
38                 mindis = dis[vex][j];
39                 min = j;
40             }
41         vis[min] = 1;
42         for(int j=1; j<=20; j++)
43             if(mindis+Map[min][j]<dis[vex][j] && Map[min][j]!=INF && vis[j]==0)
44                 dis[vex][j] = mindis+Map[min][j];
45     }
46 
47 }
48 
49 int main()
50 {
51 //    freopen("in.txt", "r", stdin);
52 
53     int vex, n;
54     while(scanf("%d", &n)!=EOF){
55         //building Map
56         init();
57         for(int i=0; i<n; i++){
58             scanf("%d", &vex);
59             Map[1][vex] = Map[vex][1] = 1;
60         }
61         for(int i=2; i<20; i++){
62             scanf("%d", &n);
63             for(int j=0; j<n; j++){
64                 scanf("%d", &vex);
65                 Map[i][vex] = Map[vex][i] = 1;
66             }
67         }
68         //solve
69         for(int i=1; i<21; i++) Dijkstra(i);
70         //Reading Questions and Output
71         int q, a, b;
72         scanf("%d", &q);
73         printf("Test Set #%d
", cnt++);
74         for(int i=0; i<q; i++){
75             scanf("%d%d", &a, &b);
76             printf("%2d to %2d: %d
", a, b, dis[a][b]);
77         }
78         printf("
");
79     }
80     return 0;
81 }
View Code

四、dijkstra算法+IO优化

第一次写IO优化表示只是读取正整数还是比较简单的。

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 #include <algorithm>
 7 #include <vector>
 8 #include <queue>
 9 #include <stack>
10 #define LEN 30
11 #define INF 0x7fffffff
12 using namespace std;
13 
14 int Map[LEN][LEN], dis[LEN][LEN], vis[LEN], cnt = 1;
15 
16 void init()
17 {
18     for(int i=0; i<=20; i++){
19         for(int j=0; j<=20; j++)
20             Map[i][j] = INF;
21         Map[i][i] = 0;
22     }
23     memset(dis, 0, sizeof dis);
24 }
25 
26 void Dijkstra(int vex)
27 {
28     memset(vis, 0, sizeof vis);
29     for(int i=1; i<=20; i++)
30         dis[vex][i] = Map[vex][i];
31     vis[vex] = 1;
32     for(int i=1; i<20 ;i++)
33     {
34         int min, mindis = INF;
35         for(int j=1; j<=20; j++)
36             if(dis[vex][j]<mindis && vis[j] == 0)
37             {
38                 mindis = dis[vex][j];
39                 min = j;
40             }
41         vis[min] = 1;
42         for(int j=1; j<=20; j++)
43             if(mindis+Map[min][j]<dis[vex][j] && Map[min][j]!=INF && vis[j]==0)
44                 dis[vex][j] = mindis+Map[min][j];
45     }
46 
47 }
48 
49 inline void read(int &ret)
50 {
51     char c;
52     while((c = getchar())<'0' || c>'9');
53     ret = 0;
54     while(c>='0' && c<='9'){
55         ret = ret*10+(c-'0');
56         c = getchar();
57     }
58 }
59 
60 int main()
61 {
62 //    freopen("in.txt", "r", stdin);
63 
64     int vex, n;
65     while(scanf("%d", &n)!=EOF){
66         //building Map
67         init();
68         for(int i=0; i<n; i++){
69             read(vex);
70             Map[1][vex] = Map[vex][1] = 1;
71         }
72         for(int i=2; i<20; i++){
73             read(n);
74             for(int j=0; j<n; j++){
75                 read(vex);
76                 Map[i][vex] = Map[vex][i] = 1;
77             }
78         }
79         //solve
80         for(int i=1; i<21; i++) Dijkstra(i);
81         //Reading Questions and Output
82         int q, a, b;
83         read(q);
84         printf("Test Set #%d", cnt++);
85         putchar('
');
86         for(int i=0; i<q; i++){
87             read(a);read(b);
88             printf("%2d to %2d: ", a, b);
89             putchar(dis[a][b]+'0');
90             putchar('
');
91         }
92         putchar('
');
93     }
94     return 0;
95 }
View Code

五、dijkstra算法+优先队列优化+IO优化

无聊的时候有换了O(mlogn)的Dij重写了一遍时间稳定在0.07左右,又快了一些。

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 #include <algorithm>
 7 #include <utility>
 8 #include <functional>
 9 #include <vector>
10 #include <queue>
11 #include <stack>
12 #define LEN 30
13 #define INF 0x7fffffff
14 using namespace std;
15 
16 int dis[LEN][LEN], vis[LEN], cnt = 1;
17 vector<int> Map[LEN];
18 typedef pair<int,int> pii;
19 
20 void init()
21 {
22     for(int i=0; i<LEN; i++)Map[i].clear();
23     memset(dis, 0, sizeof dis);
24 }
25 
26 //O(mlogn)--Dijkstra
27 void Dijkstra(int vex)
28 {
29     priority_queue<pii, vector<pii>, greater<pii> > q;
30     for(int i=0; i<21; i++)dis[vex][i] = (i==vex?0:INF);
31     memset(vis, 0, sizeof vis);
32     q.push(make_pair(dis[vex][vex], vex));
33     while(!q.empty()){
34         pii u = q.top(); q.pop();
35         int x = u.second;
36         if(vis[x]) continue;
37         vis[x] = 1;
38         for(vector<int>::iterator it = Map[x].begin(); it!=Map[x].end(); ++it){
39             if(dis[vex][*it]>dis[vex][x]+1) {
40                 dis[vex][*it] = dis[vex][x]+1;
41                 q.push(make_pair(dis[vex][*it], *it));
42             }
43         }
44     }
45 }
46 
47 inline void read(int &ret)
48 {
49     char c;
50     while((c = getchar())<'0' || c>'9');
51     ret = 0;
52     while(c>='0' && c<='9'){
53         ret = ret*10+(c-'0');
54         c = getchar();
55     }
56 }
57 
58 int main()
59 {
60 //    freopen("in.txt", "r", stdin);
61 
62     int vex, n;
63     while(scanf("%d", &n)!=EOF){
64         //building Map
65         init();
66         for(int i=0; i<n; i++){
67             read(vex);
68             Map[1].push_back(vex);
69             Map[vex].push_back(1);
70         }
71         for(int i=2; i<20; i++){
72             read(n);
73             for(int j=0; j<n; j++){
74                 read(vex);
75                 Map[i].push_back(vex);
76                 Map[vex].push_back(i);
77             }
78         }
79         //solve
80         for(int i=1; i<21; i++) Dijkstra(i);
81         //Reading Questions and Output
82         int q, a, b;
83         read(q);
84         printf("Test Set #%d", cnt++);
85         putchar('
');
86         for(int i=0; i<q; i++){
87             read(a);read(b);
88             printf("%2d to %2d: ", a, b);
89             putchar(dis[a][b]+'0');
90             putchar('
');
91         }
92         putchar('
');
93     }
94     return 0;
95 }
View Code
奔跑吧!少年!趁着你还年轻
原文地址:https://www.cnblogs.com/shu-xiaohao/p/3440474.html