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\n", 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\n", a, b, ans); 74 } 75 printf("\n"); 76 } 77 return 0; 78 }
二、简单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\n", 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\n", a, b, ans); 84 } 85 printf("\n"); 86 } 87 return 0; 88 }
三、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\n", cnt++); 74 for(int i=0; i<q; i++){ 75 scanf("%d%d", &a, &b); 76 printf("%2d to %2d: %d\n", a, b, dis[a][b]); 77 } 78 printf("\n"); 79 } 80 return 0; 81 }
四、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('\n'); 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('\n'); 91 } 92 putchar('\n'); 93 } 94 return 0; 95 }
五、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('\n'); 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('\n'); 91 } 92 putchar('\n'); 93 } 94 return 0; 95 }
奔跑吧!少年!趁着你还年轻