zoukankan      html  css  js  c++  java
  • 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
    奔跑吧!少年!趁着你还年轻
  • 相关阅读:
    【POJ3358】Period of an Infinite Binary Expansion-欧拉定理+数论好题
    【POJ3696】The Luckiest Number-欧拉定理+快速幂
    【POJ3090】Visible Lattice Points-欧拉函数应用
    【POJ3090】Visible Lattice Points-欧拉函数应用
    【POJ2891】Strange Way to Express Integers-解一元线性同余方程组
    【POJ2891】Strange Way to Express Integers-解一元线性同余方程组
    【POJ2429】GCD & LCM Inverse-Pollard-rho分解+枚举
    【POJ2429】GCD & LCM Inverse-Pollard-rho分解+枚举
    【POJ1811】Prime Test-Miller-Rabin素数测试+Pollard-rho大数分解
    deleted
  • 原文地址:https://www.cnblogs.com/shu-xiaohao/p/3440474.html
Copyright © 2011-2022 走看看