zoukankan      html  css  js  c++  java
  • ACM学习历程—HDU4725 The Shortest Path in Nya Graph(SPFA && 优先队列)

    Description

    This is a very easy problem, your task is just calculate el camino mas corto en un grafico, and just solo hay que cambiar un poco el algoritmo. If you do not understand a word of this paragraph, just move on.        The Nya graph is an undirected graph with "layers". Each node in the graph belongs to a layer, there are N nodes in total.        You can move from any node in layer x to any node in layer x + 1, with cost C, since the roads are bi-directional, moving from layer x + 1 to layer x is also allowed with the same cost.        Besides, there are M extra edges, each connecting a pair of node u and v, with cost w.        Help us calculate the shortest path from node 1 to node N.      
                  

    Input

    The first line has a number T (T <= 20) , indicating the number of test cases.        For each test case, first line has three numbers N, M (0 <= N, M <= 10 5) and C(1 <= C <= 10 3), which is the number of nodes, the number of extra edges and cost of moving between adjacent layers.        The second line has N numbers l i (1 <= l i <= N), which is the layer of i th node belong to.        Then come N lines each with 3 numbers, u, v (1 <= u, v < =N, u <> v) and w (1 <= w <= 10 4), which means there is an extra edge, connecting a pair of node u and v, with cost w.      
                  

    Output

    For test case X, output "Case #X: " first, then output the minimum cost moving from node 1 to node N.        If there are no solutions, output -1.      
                  

    Sample Input

    2
    3 3 3
    1 3 2
    1 2 1
    2 3 1
    1 3 3
     
    3 3 3
    1 3 2
    1 2 2
    2 3 2
    1 3 4
                  

    Sample Output

    Case #1: 2
    Case #2: 3

    题目大意是是有n层。然后每层会有部分点,点与点可以通过特点的代价互达,相邻层之间的点可以通过C代价到达。

    题目一开始没有看到每层可以有多个点。还有需要注意的是同层之间的点不能直接0代价到达。

    之前在没考虑同层间不能直接0代价互达的时候,是把每个层看作一个节点,这样某层的节点到这个节点的代价都是0。

    如果考虑到这个条件的话,

    所以需要构造出下面这样的路径:

    为每层设置From和To节点。某层的节点只能从From节点前往,或者前往To节点。

    而相邻层之间亦是如此。

    这样就能避免同层代价为0这个问题了。

    为了避免点的冲突,From从n开始往后,To从2n开始往后。

    需要注意的是这样操作以后点的数目上界会变成3N,线段就是6N。

    这里采用链式前向星存图,采用STL优先队列的SPFA。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <utility>
    #include <queue>
    #include <vector>
    #define N 300005
    
    using namespace std;
    
    typedef pair<int, int> pii;
    
    struct Edge
    {
        int to;
        int next;
        int val;
    }edge[2*N];
    
    int head[N], cnt;
    
    void addEdge(int u, int v, int w)
    {
        edge[cnt].to = v;
        edge[cnt].next = head[u];
        edge[cnt].val = w;
        head[u] = cnt;
        cnt++;
    }
    
    int dis[N];
    bool vis[N];
    int n, m, c;
    
    inline int idFrom(int i)
    {
        return i + n;
    }
    
    inline int idTo(int i)
    {
        return i + 2*n;
    }
    
    void Input()
    {
        memset(head, -1, sizeof(head));
        memset(dis, -1, sizeof(dis));
        memset(vis, 0, sizeof(vis));
        dis[1] = 0;
        cnt = 0;
        int k, v, w;
        scanf("%d%d%d", &n, &m, &c);
        for (int i = 1; i <= n; ++i)
        {
            scanf("%d", &k);
            addEdge(idFrom(k), i, 0);
            addEdge(i, idTo(k), 0);
        }
        for (int i = 1; i < n; ++i)
        {
            addEdge(idTo(i), idFrom(i+1), c);
            addEdge(idTo(i+1), idFrom(i), c);
        }
        for (int i = 0; i < m; ++i)
        {
            scanf("%d%d%d", &k, &v, &w);
            addEdge(k, v, w);
            addEdge(v, k, w);
        }
    }
    
    void Work()
    {
        pii k;
        priority_queue <pii, vector<pii>, greater<pii> > q;
        q.push(pii(0, 1));
        while (!q.empty())
        {
            k = q.top();
            q.pop();
            int x = k.second;
            if (vis[x])
                continue;
            vis[x] = true;
            for (int i = head[x]; i != -1; i = edge[i].next)
            {
                if (dis[edge[i].to] != -1 &&
                    dis[edge[i].to] <= dis[x] + edge[i].val)
                    continue;
                if (vis[edge[i].to])
                    continue;
                dis[edge[i].to] = dis[x] + edge[i].val;
                q.push(pii(dis[edge[i].to], edge[i].to));
            }
        }
        printf("%d
    ", dis[n]);
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        int T;
        scanf("%d", &T);
        for (int times = 1; times <= T; ++times)
        {
            printf("Case #%d: ", times);
            Input();
            Work();
        }
        return 0;
    }
  • 相关阅读:
    【转】 矩阵构造方法
    CODEVS1187 Xor最大路径 (Trie树)
    POJ2001 Shortest Prefixes (Trie树)
    CODEVS1079 回家 (最短路)
    CODEVS2144 砝码称重2 (哈希表)
    CODEVS1380 没有上司的舞会 (树形DP)
    JAVA 多态和异常处理作业——动手动脑以及课后实验性问题
    再读大道之简第七章第八章
    JAVA 接口与继承作业——动手动脑以及课后实验性问题
    再读大道至简第六章
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/4531832.html
Copyright © 2011-2022 走看看