zoukankan      html  css  js  c++  java
  • BZOJ1579 USACO 2009 Feb Gold 3.Revamping Trails Solution

    标题效果:一个N积分m无向图边。它可以是路径k右边缘值变0,确定此时1-n最短路径长度。


    Sol:我以为我们考虑分层图,图复制k+1部分,每间0~k一层。代表在这个时候已经过去“自由边缘”文章编号。

    层与层之间的边权值为0且为单向由上层指向下层。

    这样我们以0层的1点做单源最短路径。每一层的n点的距离最小值即为答案。

    仅仅只是这种点数为O(K*N),边数为O(K*M),比較慢。


    我的做法是,对每一层使用heap-dijkstra算法由本层的原点更新这一层的最短路长度。然后显然能够用O(m)的复杂度推知下一层的初始最短路长度。

    这样的做法显然空间和时间上均存在较大优势。


    Code:

    #include <cstdio>
    #include <cstring>
    #include <cctype>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    using namespace std;
     
    inline int getc() {
        static const int L = 1 << 15;
        static char buf[L], *S = buf, *T = buf;
        if (S == T) {
            T = (S = buf) + fread(buf, 1, L, stdin);
            if (S == T)
                return EOF;
        }
        return *S++;
    }
    inline int getint() {
        int c;
        while(!isdigit(c = getc()));
        int tmp = c - '0';
        while(isdigit(c = getc()))
            tmp = (tmp << 1) + (tmp << 3) + c - '0';
        return tmp;
    }
     
    typedef long long LL;
     
    #define N 10010
    #define M 50010
    int n, m, k;
    int head[N], next[M << 1], end[M << 1], len[M << 1];
    LL dis[2][N];
    bool inpath[N];
     
    queue<int> q;
     
    void addedge(int a, int b, int _len) {
        static int q = 1;
        len[q] = _len;
        end[q] = b;
        next[q] = head[a];
        head[a] = q++;
    }
    void make(int a, int b, int _len) {
        addedge(a, b, _len);
        addedge(b, a, _len);
    }
     
    struct Node {
        int lab, dis;
        Node(int _lab = 0, int _dis = 0):lab(_lab),dis(_dis){}
        bool operator < (const Node &B) const {
            return (dis < B.dis) || (dis == B.dis && lab < B.lab);
        }
    };
    struct Heap {
        Node a[N];
        int top, ch[N];
        Heap():top(0){}
        void up(int x) {
            for(; x != 1; x >>= 1) {
                if (a[x] < a[x >> 1]) {
                    swap(ch[a[x].lab], ch[a[x >> 1].lab]);
                    swap(a[x], a[x >> 1]);
                }
                else
                    break;
            }
        }
        void down(int x) {
            int son;
            for(; x << 1 <= top; ) {
                son=(((x<<1)==top)||(a[x<<1]<a[(x<<1)|1]))?(x<<1):((x<<1)|1);
                if (a[son] < a[x]) {
                    swap(ch[a[son].lab], ch[a[x].lab]);
                    swap(a[son], a[x]);
                    x = son;
                }
                else
                    break;
            }
        }
        void insert(Node x) {
            a[++top] = x;
            ch[x.lab] = top;
            up(top);
        }
        Node Min() {
            return a[1];
        }
        void pop() {
            a[1] = a[top];
            ch[a[top--].lab] = 1;
            down(1);
        }
        void change(int x, int to) {
            int ins = ch[x];
            a[ins].dis = to;
            up(ins);
        }
    }H;
     
    void Dijkstra(bool d) {
        H.top = 0;
        int i, j;
        memset(inpath, 0, sizeof(inpath));
        for(i = 1; i <= n; ++i)
            H.insert(Node(i, dis[d][i]));
        for(i = 1; i <= n; ++i) {
            Node tmp = H.Min();
            H.pop();
            inpath[tmp.lab] = 1;
            for(j = head[tmp.lab]; j; j = next[j]) {
                if (!inpath[end[j]] && dis[d][end[j]] > dis[d][tmp.lab] + len[j]) {
                    dis[d][end[j]] = dis[d][tmp.lab] + len[j];
                    H.change(end[j], dis[d][end[j]]);
                }
            }
        }
    }
     
    int main() {
        n = getint();
        m = getint();
        k = getint();
         
        int i, j;
        int a, b, x;
        for(i = 1; i <= m; ++i) {
            a = getint();
            b = getint();
            x = getint();
            make(a, b, x);
        }
         
        int now = 0, last = 1;
         
        memset(dis, 0x3f, sizeof(dis));
        dis[now][1] = 0;
        Dijkstra(now);
        LL ans = dis[now][n];
         
        while(k--) {
            now ^= 1;
            last ^= 1;
            for(i = 1; i <= n; ++i)
                dis[now][i] = dis[last][i];
            for(i = 1; i <= n; ++i)
                for(j = head[i]; j; j = next[j])
                    dis[now][end[j]] = min(dis[now][end[j]], dis[last][i]);
            Dijkstra(now);
            if (ans == dis[now][n])
                break;
            ans = dis[now][n];
        }
         
        printf("%lld", ans);
         
        return 0;
    }

    版权声明:本文博主原创文章。博客,未经同意不得转载。

  • 相关阅读:
    codevs 3657 括号序列
    洛谷P1962 斐波那契数列
    Black Rock shooter
    codevs 2596 售货员的难题
    51Nod-1154 回文串划分
    UVA
    POJ3321[苹果树] 树状数组/线段树 + dfs序
    Hdu 4578 Transformation (线段树 分类分析)
    786B
    438D
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4800615.html
Copyright © 2011-2022 走看看