zoukankan      html  css  js  c++  java
  • POJ 2449 Remmarguts' Date

    POJ_2449

        一开始我的思路就是把图上每个点搞一个容量不小于K的最大堆和最小堆,最小堆用于取当前该节点的第某短路值,最大堆用来保存前K小的最短路。

        最后为了每次能查询全局最小值,再把N个点放到一个线段树(最小堆)上即可,剩下的工作就是进行dij的过程了,当访问终点的次数达到第K次时break即可,这时就是第K短路的值了。

        但这样会TLE,所以还是要用A*算法。

        感觉A*就像是个优先级队列,从这个角度讲,dij本来也是A*算法,只不过其估价函数就等于起点到该点的最短距离。

        而这个题目需要变一下估价函数,设g[i]为由某条路线从S到i点的路径长度,d[i]表示i点到T的最短路,那么我们把g[i]+d[i]作为估价函数,而其他的步骤和dij都是一样的,在第K次搜到终点的时候退出即可。

        这样做相比用g[i]作为估计函数是更好的。首先g[i]+d[i]实际反映的是一条路径的长度,是从路径的角度着眼的。同时,d[i]表示的是当前走了g[i]到达i点的情况下,最快还需要走多少到达终点,那么如果g[i]+d[i]都不能作为K短路之内的路径的话,那么我们自然不用再从g[i]开始拓展了,因为这样拓展的话最终长度至少是g[i]+d[i],这样就完成了一个剪枝。

        至于为什么第K次搜到终点的时候退出即可,这个不难理解。因为对任意一个点i,d[i]是定值,那么第K小的g[i]+d[i]中的g[i]自然就是第K小的g[],也就是第K短路。

    #include<stdio.h>
    #include<string.h>
    #define MAXD 1010
    #define MAXM 100010
    #define MAXT 2050
    #define MAXK 1010
    #define INF 0x3f3f3f3f
    int DI, DO, N, M, K, S, T, first[MAXD], next[MAXM], v[MAXM], w[MAXM], tree[MAXT], e;
    int nf[MAXD], nn[MAXM], nv[MAXM], nw[MAXM], d[MAXD];
    struct Tree
    {
    int dis, min, min_tree[MAXT], max_tree[MAXT], a[MAXT];
    void init()
    {
    int i;
    min = dis = INF;
    for(i = 0; i < DI; i ++)
    {
    min_tree[i + DI] = max_tree[i + DI] = i;
    a[i] = INF;
    }
    for(i = DI - 1; i > 0; i --)
    {
    min_tree[i] = min_tree[i << 1];
    max_tree[i] = max_tree[i << 1];
    }
    }
    void update_min(int i)
    {
    for(; i ^ 1; i >>= 1)
    min_tree[i >> 1] = a[min_tree[i]] < a[min_tree[i ^ 1]] ? min_tree[i] : min_tree[i ^ 1];
    }
    void update_max(int i)
    {
    for(; i ^ 1; i >>= 1)
    max_tree[i >> 1] = a[max_tree[i]] > a[max_tree[i ^ 1]] ? max_tree[i] : max_tree[i ^ 1];
    }
    int Insert(int x, int i)
    {
    int k = max_tree[1];
    if(x < a[k])
    {
    a[k] = x, update_max(DI + k), update_min(DI + k);
    if(x < min)
    {
    min = x;
    dis = min - d[i];
    return 1;
    }
    }
    return 0;
    }
    void Delete(int i)
    {
    int k = min_tree[1];
    a[k] = INF, update_min(DI + k);
    min = a[min_tree[1]];
    dis = min - d[i];
    }
    }t[MAXT];
    void add(int x, int y, int z)
    {
    w[e] = z, v[e] = y;
    next[e] = first[x], first[x] = e;
    nw[e] = z, nv[e] = x;
    nn[e] = nf[y], nf[y] = e;
    ++ e;
    }
    void init()
    {
    int i, j, k, x, y, z;
    for(DO = 1; DO <= N; DO <<= 1);
    memset(first + 1, -1, sizeof(first[0]) * N);
    memset(nf + 1, -1, sizeof(nf[0]) * N);
    e = 0;
    for(i = 0; i < M; i ++)
    {
    scanf("%d%d%d", &x, &y, &z);
    add(x, y, z);
    }
    scanf("%d%d%d", &S, &T, &K);
    for(DI = 1; DI < K; DI <<= 1);
    }
    void dij_update(int i)
    {
    for(; i ^ 1; i >>= 1)
    tree[i >> 1] = d[tree[i]] < d[tree[i ^ 1]] ? tree[i] : tree[i ^ 1];
    }
    void dij()
    {
    int i, j, k, x;
    d[0] = INF;
    memset(tree + 1, 0, sizeof(tree[0]) * (DO << 1));
    memset(d + 1, 0x3f, sizeof(d[0]) * N);
    d[T] = 0, tree[T + DO] = T, dij_update(T + DO);
    while(x = tree[1])
    {
    for(i = nf[x]; i != -1; i = nn[i])
    if(d[x] + nw[i] < d[nv[i]])
    {
    d[nv[i]] = d[x] + nw[i];
    tree[nv[i] + DO] = nv[i], dij_update(nv[i] + DO);
    }
    tree[x + DO] = 0, dij_update(x + DO);
    }
    }
    void update(int i)
    {
    for(; i ^ 1; i >>= 1)
    tree[i >> 1] = t[tree[i]].min < t[tree[i ^ 1]].min ? tree[i] : tree[i ^ 1];
    }
    void solve()
    {
    int i, j, k, cnt, x, y, z;
    dij();
    memset(tree + 1, 0, sizeof(tree[0]) * (DO << 1));
    for(i = 0; i < DO; i ++)
    {
    t[i].init();
    tree[i + DO] = i;
    }
    for(i = DO - 1; i > 0; i --)
    tree[i] = tree[i << 1];
    t[S].Insert(d[S], S), update(S + DO);
    cnt = S == T ? -1 : 0;
    while(t[x = tree[1]].min != INF)
    {
    if(x == T)
    {
    if(++ cnt == K)
    break;
    }
    for(i = first[x]; i != -1; i = next[i])
    if(t[v[i]].Insert(t[x].dis + w[i] + d[v[i]], v[i]))
    update(v[i] + DO);
    t[x].Delete(x), update(x + DO);
    }
    if(cnt == K)
    printf("%d\n", t[tree[1]].dis);
    else
    printf("-1\n");
    }
    int main()
    {
    while(scanf("%d%d", &N, &M) == 2)
    {
    init();
    solve();
    }
    return 0;
    }


  • 相关阅读:
    Eclipse CDT 调试故障解决:Can't find resource for bundle java.util.PropertyResourceBundle
    winpcap 枚举网卡设备Demo
    ORCA msi修改工具 解决 msn 卡巴斯基 iTune等不能在Windows Server 2003下安装的问题
    收藏 彩色转灰度的舍入问题
    C++之仿函数
    CTreeCtrl icon 背景透明 解决方法
    colinux 运行和配置
    生成COM Dll的tlb文件的两种方法
    windows下建立gcc/g++/gdb/make编译及调试C/C++的IDE环境
    使用伪寄存器调试MSVC++程序的介绍An introduction to debugging in MSVC++ using Pseudoregisters
  • 原文地址:https://www.cnblogs.com/staginner/p/2422579.html
Copyright © 2011-2022 走看看