• POJ 1724 ROADS


    POJ_1724

        这个题目可以直接将SPFA中的dis[]变成二维的dis[i][k]表示到第i个点花费为k时的最短路,但如果直接做SPFA会超时,需要加一个剪枝:设mind[i]表示到第i个点的用于剪枝最短路,mink[i] 表示第i个点的用于剪枝的最小花费,如果在SPFA的过程中走到了第i个点的路径长为d花费为k,那么如果d>=mind[i]&&k>=mink[i],这时就进行剪枝,如果d<mind[i]&&k<mink[i]就更新mind[i]与mink[i]的值,并将这个点(i,k)入队,其余的情况也要将(i,k)入队。

        这个题目还可以用堆形式的SPFA去做,这时需要把N个点看成N*(K+1)个点,且堆顶的元素为当前所有点中dis[]的值最小的一个。其余的操作和SPFA大体相同,这时同样有一个剪枝:如果堆顶的元素是标号为N的点,那么就可以直接结束SPFA了。

    //普通的SPFA
    #include<stdio.h>
    #include<string.h>
    #define MAXD 110
    #define MAXK 10010
    #define MAXM 10010
    #define MAXQ 1000110
    #define INF 0x3f3f3f3f
    int N, M, K, first[MAXD], next[MAXM], v[MAXM], w[MAXM], cost[MAXM], e, q[MAXQ], m[MAXQ], inq[MAXD][MAXK], d[MAXD][MAXK], mind[MAXD], mink[MAXD], Q = 1000100;
    void add(int &x, int &y, int &z, int &t)
    {
    v[e] = y;
    w[e] = z;
    cost[e] = t;
    next[e] = first[x];
    first[x] = e;
    ++ e;
    }
    void init()
    {
    int i, j, k, x, y, z, t;
    e = 0;
    memset(first, -1, sizeof(first));
    scanf("%d%d", &N, &M);
    for(i = 0; i < M; i ++)
    {
    scanf("%d%d%d%d", &x, &y, &z, &t);
    add(x, y, z, t);
    }
    }
    void solve()
    {
    int i, j, k, x, y, z, newk, front ,rear, ans;
    front = rear = 0;
    for(i = 1; i <= N; i ++)
    for(j = 0; j <= K; j ++)
    d[i][j] = INF, inq[i][j] = 0;
    memset(mind, 0x3f, sizeof(mind));
    memset(mink, 0x3f, sizeof(mink));
    q[rear] = 1, m[rear] = 0, d[1][0] = 0;
    ++ rear;
    mind[1] = mink[1] = 0;
    while(front != rear)
    {
    x = q[front], k = m[front];
    inq[x][k] = 0;
    ++ front;
    if(front > Q)
    front = 0;
    for(i = first[x]; i != -1; i = next[i])
    {
    y = v[i], newk = k + cost[i], z= d[x][k] + w[i];
    if(newk <= K && z < d[y][newk])
    {
    if(z >= mind[y] && newk >= mink[y])
    continue;
    if(z < mind[y] && newk < mink[y])
    mind[y] = z, mink[y] = newk;
    d[y][newk] = z;
    if(!inq[y][newk])
    {
    q[rear] = y;
    m[rear] = newk;
    inq[y][newk] = 1;
    ++ rear;
    if(rear > Q)
    rear = 0;
    }
    }
    }
    }
    ans = INF;
    for(i = 0; i <= K; i ++)
    if(d[N][i] < ans)
    ans = d[N][i];
    printf("%d\n", ans == INF ? -1 : ans);
    }
    int main()
    {
    while(scanf("%d", &K) == 1)
    {
    init();
    solve();
    }
    return 0;
    }
    //堆形式的SPFA
    #include<stdio.h>
    #include<string.h>
    #define MAXD 110
    #define MAX 4000410
    #define MAXM 10010
    #define INF 0x3f3f3f3f
    int N, M, K, first[MAXD], next[MAXM], v[MAXM], w[MAXM], cost[MAXM], P, f[MAX], d[MAX], m[MAX], tree[MAX], mind[MAXD], mink[MAXD];
    void init()
    {
    int i, j, k, x, y, z, t;
    memset(first, -1, sizeof(first));
    scanf("%d%d", &N, &M);
    for(i = 0; i < M; i ++)
    {
    scanf("%d%d%d%d", &x, &y, &z, &t);
    v[i] = y;
    w[i] = z;
    cost[i] = t;
    next[i] = first[x];
    first[x] = i;
    }
    }
    void insert(int cur, int dis, int k)
    {
    int i, left, right, s = k * N + cur;
    if(dis < d[s])
    {
    f[s] = cur;
    d[s] = dis;
    m[s] = k;
    i = P + s;
    if(!tree[i])
    {
    tree[i] = s;
    for(i >>= 1; i > 0; i >>= 1)
    {
    left = tree[2 * i], right = tree[2 * i + 1];
    tree[i] = d[left] < d[right] ? left : right;
    }
    }
    }
    }
    void update()
    {
    int i, left, right, s = tree[1];
    i = P + s;
    tree[i] = 0;
    for(i >>= 1; i > 0; i >>= 1)
    {
    left = tree[2 * i], right = tree[2 * i + 1];
    tree[i] = d[left] < d[right] ? left : right;
    }
    }
    void solve()
    {
    int i, j, k, x, y, z, s, t, ans;
    memset(mind, 0x3f, sizeof(mind));
    memset(mink, 0x3f, sizeof(mink));
    for(P = 1; P < (K + 1) * N + 2; P <<= 1);
    for(i = (K + 1) * N; i >= 0; i --)
    d[i] = INF;
    for(i = 2 * P - 1; i > 0; i --)
    tree[i] = 0;
    d[0] = m[0] = INF;
    insert(1, 0, 0);
    mind[1] = mink[1] = 0;
    while(tree[1])
    {
    s = tree[1];
    if(s % N == 0)
    break;
    update();
    x = f[s], k = m[s];
    for(i = first[x]; i != -1; i = next[i])
    {
    y = v[i], z = d[s] + w[i], t = k + cost[i];
    if(t <= K)
    {
    if(z >= mind[y] && t >= mink[y])
    continue;
    if(z < mind[y] && t < mink[y])
    mind[y] = z, mink[y] = t;
    insert(y, z, t);
    }
    }
    }
    printf("%d\n", tree[1] ? d[s] : -1);
    }
    int main()
    {
    while(scanf("%d", &K) == 1)
    {
    init();
    solve();
    }
    return 0;
    }



  • 相关阅读:
    面向对象的继承关系体现在数据结构上时,如何表示
    codeforces 584C Marina and Vasya
    codeforces 602A Two Bases
    LA 4329 PingPong
    codeforces 584B Kolya and Tanya
    codeforces 584A Olesya and Rodion
    codeforces 583B Robot's Task
    codeforces 583A Asphalting Roads
    codeforces 581C Developing Skills
    codeforces 581A Vasya the Hipster
  • 原文地址:https://www.cnblogs.com/staginner/p/2332493.html
Copyright © 2020-2023  润新知