• ACM/ICPC 之 最短路-SPFA+正逆邻接表(POJ1511(ZOJ2008))


    求单源最短路到其余各点,然后返回源点的总最短路长,以构造邻接表的方法不同分为两种解法。


    POJ1511(ZOJ2008)-Invitation Cards

      改变构造邻接表的方法后,分为两种解法

    解法一:

     1 //POJ1511-ZOJ2008
     2 //Time:7766Ms    Memory:99112K
     3 //求从1处到各点后再返回1处的最短总路长
     4 //需要构造邻接表和逆邻接表
     5 //构造方法1:vector构造邻接表
     6 //SPFA+邻接表
     7 #include<iostream>
     8 #include<cstring>
     9 #include<cstdio>
    10 #include<vector>
    11 #include<queue>
    12 using namespace std;
    13 
    14 #define MAX 1000005
    15 #define INF 0x3f3f3f3f
    16 
    17 struct Edge {
    18     int u, w;
    19     Edge(int uu, int ww) :u(uu), w(ww) {}
    20 };
    21 
    22 vector<Edge> e1[MAX], e2[MAX];    //邻接表-逆邻接表
    23 
    24 int n, m;
    25 int d[MAX];
    26 long long sum;
    27 bool v[MAX];
    28 
    29 void SPFA(int x, vector<Edge> e[MAX])
    30 {
    31     memset(d, INF, sizeof(d));
    32     memset(v, false, sizeof(v));
    33     queue<int> q;
    34     q.push(x);
    35     d[x] = 0;
    36     while (!q.empty()){
    37         int cur = q.front();
    38         q.pop();
    39         v[cur] = false;
    40         for (int i = 0; i < e[cur].size(); i++)
    41         {
    42             int u = e[cur][i].u;
    43             if (d[u] > d[cur] + e[cur][i].w)
    44             {
    45                 d[u] = d[cur] + e[cur][i].w;
    46                 if (!v[u]) { q.push(u); v[u] = true; }
    47             }
    48         }
    49     }
    50     for (int i = 2; i <= n; i++)
    51         sum += d[i];
    52 }
    53 
    54 int main()
    55 {
    56     int T;
    57     scanf("%d", &T);
    58     while (T--) {
    59         sum = 0;
    60         memset(e1, 0, sizeof(e1));
    61         memset(e2, 0, sizeof(e2));
    62         scanf("%d%d", &n, &m);
    63         while (m--) {
    64             int u, v, w;
    65             scanf("%d%d%d", &u, &v, &w);
    66             e1[u].push_back(Edge(v, w));    //正向
    67             e2[v].push_back(Edge(u, w));    //逆向
    68         }
    69         
    70         SPFA(1, e1);
    71         SPFA(1, e2);
    72         printf("%lld
    ", sum);
    73     }
    74     
    75     return 0;
    76 }

    解法二:

     1 //POJ1511-ZOJ2008
     2 //Time:2000Ms    Memory:36424K
     3 //求从1处到各点后再返回1处的最短总路长
     4 //需要构造邻接表和逆邻接表
     5 //构造方法2:偏序关系构造邻接表
     6 //SPFA+邻接表
     7 #include<iostream>
     8 #include<cstring>
     9 #include<cstdio>
    10 #include<vector>
    11 #include<queue>
    12 using namespace std;
    13 
    14 #define MAX 1000005
    15 #define INF 0x3f3f3f3f
    16 
    17 struct Edge {
    18     int u, w, next;
    19     Edge() {}
    20     Edge(int uu, int ww, int nn) :u(uu), w(ww), next(nn) {}
    21 }e1[MAX], e2[MAX];    //邻接表-逆邻接表
    22 
    23 int h1[MAX], h2[MAX];    //正表表头-逆表表头
    24 int n, m;
    25 int d[MAX];
    26 long long sum;
    27 bool v[MAX];
    28 
    29 void SPFA(int x, Edge e[MAX], int h[MAX])
    30 {
    31     memset(d, INF, sizeof(d));
    32     memset(v, false, sizeof(v));
    33     queue<int> q;
    34     q.push(x);
    35     d[x] = 0;
    36     while (!q.empty()){
    37         int cur = q.front();
    38         q.pop();
    39         v[cur] = false;
    40         for (int i = h[cur]; i != -1; i = e[i].next)
    41         {
    42             int u = e[i].u;
    43             int w = e[i].w;
    44             if (d[u] > d[cur] + w)
    45             {
    46                 d[u] = d[cur] + w;
    47                 if (!v[u]) { q.push(u); v[u] = true; }
    48             }
    49         }
    50     }
    51     for (int i = 2; i <= n; i++)
    52         sum += d[i];
    53 }
    54 
    55 int main()
    56 {
    57     int T;
    58     scanf("%d", &T);
    59     while (T--) {
    60         sum = 0;
    61         memset(e1, 0, sizeof(e1));
    62         memset(e2, 0, sizeof(e2));
    63         memset(h1, -1, sizeof(h1));
    64         memset(h2, -1, sizeof(h2));
    65         scanf("%d%d", &n, &m);
    66         for (int i = 0; i < m; i++) {
    67             int u, v, w;
    68             scanf("%d%d%d", &u, &v, &w);
    69             e1[i] = Edge(v, w, h1[u]);
    70             e2[i] = Edge(u, w, h2[v]);
    71             h1[u] = h2[v] = i;
    72         }
    73         
    74         SPFA(1, e1, h1);
    75         SPFA(1, e2, h2);
    76         printf("%lld
    ", sum);
    77     }
    78     
    79     return 0;
    80 }
  • 相关阅读:
    母爱——值得你用一生去回报
    cmd命令介绍
    对即将步入软件行业的师弟师妹们的忠告
    推荐4本c语言宝书
    不用判断语句如if,?:等来实现比较2个数
    javascript 浏览器不同的一个差异
    更新数据的经典代码
    允许 ASP.NET 服务器控件在 Page 中发出客户端脚本块的方法Page.RegisterClientScriptBlock 方法 [C#]
    使用多个表进行查询
    根据按钮的不同的CommandArgument处理每个按钮的单击事件的代码
  • 原文地址:https://www.cnblogs.com/Inkblots/p/5452452.html
Copyright © 2020-2023  润新知