• poj3268 Silver Cow Party(两次SPFA || 两次Dijkstra)


    题目链接

    http://poj.org/problem?id=3268

    题意

    有向图中有n个结点,编号1~n,输入终点编号x,求其他结点到x结点来回最短路长度的最大值。

    思路

    最短路问题,有1000个结点,Floyd算法应该会超时,我刚开始使用的Dijkstra算法也超时,原因是因为我使用一个循环遍历结点1~n,每次遍历我都使用两次Dijkstra求i到x和x到i的最短路,时间复杂度太高。降低时间复杂度的方法是先在原矩阵的基础上使用dijkstra求结点x到其余各点的最短路径,然后将矩阵转置,在转置矩阵的基础上使用dijkstra求结点x到其余各点的最短路径,这就相当于在原矩阵上求其余各点到x的最短路径,将两次得到的最短路径的值相加取最大值即可。这题也可以使用SPFA算法解决。

    代码

    SPFA算法:

     1 #include <algorithm>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <cstdio>
     5 #include <queue>
     6 #include <vector>
     7 using namespace std;
     8 
     9 struct Edge
    10 {
    11     int s, e, dist;
    12 
    13     Edge() {}
    14     Edge(int s, int e, int d) :s(s), e(e), dist(d) {}
    15 };
    16 
    17 const int INF = 0x3f3f3f;
    18 const int N = 1000 + 10;
    19 vector<Edge> v[N];
    20 int dist[N];
    21 int visit[N];
    22 int n, m, x;
    23 
    24 int spfa(int s, int e)    //返回从结点s到结点e的最短路
    25 {
    26     queue<int> q;
    27     memset(visit, 0, sizeof(visit));
    28     memset(dist, INF, sizeof(dist));
    29     q.push(s);
    30     visit[s] = 1;
    31     dist[s] = 0;
    32 
    33     while (!q.empty())
    34     {
    35         int s = q.front();
    36         q.pop();
    37         visit[s] = 0;
    38         for (int i = 0; i < v[s].size(); i++)
    39         {
    40             int e = v[s][i].e;
    41             if (dist[e] > dist[s] + v[s][i].dist)
    42             {
    43                 dist[e] = dist[s] + v[s][i].dist;
    44                 if (!visit[e])
    45                 {
    46                     visit[e] = 1;
    47                     q.push(e);
    48                 }
    49             }
    50         }
    51     }
    52     return dist[e];
    53 }
    54 
    55 int main()
    56 {
    57     //freopen("poj3268.txt", "r", stdin);
    58     while (scanf("%d%d%d", &n, &m, &x) == 3)
    59     {
    60         int a, b, d;
    61         for (int i = 0; i < m; i++)
    62         {
    63             scanf("%d%d%d", &a, &b, &d);
    64             v[a].push_back(Edge(a, b, d));
    65         }
    66         int ans = -1;
    67         for (int i = 1; i <= n; i++)
    68         {
    69             if (i != x)
    70             {
    71                 int dist1 = spfa(i, x);
    72                 int dist2 = spfa(x, i);
    73                 ans = max(ans, dist1 + dist2);
    74             }
    75         }
    76         printf("%d
    ", ans);
    77     }
    78     return 0;
    79 }

    Dijkstra算法:

     1 #include <algorithm>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <cstdio>
     5 using namespace std;
     6 
     7 const int INF = 0x3f3f3f;
     8 const int N = 1000 + 10;
     9 int map[N][N];
    10 int dist[N], reverse_dist[N];    //记录x到其余各点的最短路径,和其余各点到x的最短路径
    11 int visit[N];
    12 int n, m, x;
    13 
    14 void dijkstra(int s)
    15 {
    16     memset(visit, 0, sizeof(visit));
    17     for (int i = 1; i <= n; i++)
    18         dist[i] = map[s][i];
    19     dist[s] = 0;
    20     visit[s] = 1;
    21 
    22     int min_dist, now = s;
    23     for (int i = 1;i <= n; i++)
    24     {
    25         min_dist = INF;
    26         for (int j = 1; j <= n; j++)
    27         {
    28             if (!visit[j] && dist[j] < min_dist)
    29             {
    30                 min_dist = dist[j];
    31                 now = j;
    32             }
    33         }
    34         if (min_dist == INF) break;
    35         visit[now] = 1;
    36         for (int j = 1; j <= n; j++)
    37             dist[j] = min(dist[j], dist[now] + map[now][j]);
    38     }
    39 }
    40 
    41 void reverse_map()    //将原矩阵转置
    42 {
    43     for (int i = 1;i <= n; i++)
    44     {
    45         for (int j = i + 1; j <= n; j++)
    46         {
    47             int t = map[i][j];
    48             map[i][j] = map[j][i];
    49             map[j][i] = t;
    50         }
    51     }
    52 }
    53 
    54 int main()
    55 {
    56     //freopen("poj3268.txt", "r", stdin);
    57     while (scanf("%d%d%d", &n, &m, &x) == 3)
    58     {
    59         memset(map, INF, sizeof(map));
    60         int a, b, d;
    61         for (int i = 0; i < m; i++)
    62         {
    63             scanf("%d%d%d", &a, &b, &d);
    64             map[a][b] = d;
    65         }
    66         dijkstra(x);
    67         for (int i = 1; i <= n; i++)
    68             reverse_dist[i] = dist[i];
    69         reverse_map();
    70         dijkstra(x);
    71         int ans = -1;
    72         for (int i = 1; i <= n; i++)
    73             if (i != x)
    74                 ans = max(ans, dist[i] + reverse_dist[i]);
    75         printf("%d
    ", ans);
    76     }
    77     return 0;
    78 }
  • 相关阅读:
    嵌套查询别名必须性示例。HAVING用法
    分组查询限制。HAVING可写在GROUP BY前。
    合并查询结果集UNION(去重), UNION ALL(不去重),INTERSECT(交集),MINUS(差集,第一个结果集减去第二个结果集,第一个结果集中不在第二个结果集中的记录行),[NOT] EXIST
    18-matlab知识点复习一
    53-java中的queue
    52-2018 蓝桥杯省赛 B 组模拟赛(一)java
    51-迷宫(一)- java版dfs和bfs
    50-2018 蓝桥杯省赛 B 组模拟赛(五)
    49-2015年第6届蓝桥杯Java B组
    46-web页面登入前和登入后控制
  • 原文地址:https://www.cnblogs.com/sench/p/7979311.html
Copyright © 2020-2023  润新知