• 【BZOJ】1598: [Usaco2008 Mar]牛跑步


    【题意】给定有向图,边严格从大编号指向小编号,求前k短路。n<=1000,m<=10000,k<=100。

    【算法】归并+拓扑排序||A*求第k短路

    【题解】因为此题自带拓扑序的特殊性,可以用归并写。

    f[i][j]表示从i出发的第j短路,将i出去的点的前k短路依次归并。

    复杂度O(m*k)。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cctype>
    using namespace std;
    const int maxn=1010,maxk=110;
    struct edge{int v,from,w;}e[10010];
    
    int g[maxn][maxk],n,m,k,tot,first[maxn],b[maxn],c[maxn];
    
    int read(){
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    void insert(int u,int v,int w){tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;}
    void merge(int a[],int b[],int w){
        int l=1,r=1;
        for(int i=1;i<=k;i++){
            if(a[l]<b[r]+w)c[i]=a[l++];else c[i]=b[r++]+w;
        }
        for(int i=1;i<=k;i++)a[i]=c[i];
    }
    int main(){
        n=read();m=read();k=read();
        for(int i=1;i<=m;i++){
            int u=read(),v=read(),w=read();
            insert(u,v,w);
        }
        memset(g,0x3f,sizeof(g));
        g[1][1]=0;
        for(int x=2;x<=n;x++){
            for(int i=first[x];i;i=e[i].from){
                merge(g[x],g[e[i].v],e[i].w);
            }
        }
        for(int i=1;i<=k;i++)if(g[n][i]<0x3f3f3f3f)printf("%d
    ",g[n][i]);else printf("-1
    ");
        return 0;
    }
    View Code

    启发式搜索留坑:BZOJ 1598 牛跑步

    大概做法是f(x)=h(x)+g(x),其中h(x)是到终点估价。

    这里采用从终点反跑最短路实现精确估价,然后根据A*的性质,第k次访问终点就是第k短路。

  • 相关阅读:
    博客园
    未释放的已删除文件
    ssh连接缓慢
    剑指 Offer 38. 字符串的排列
    剑指 Offer 37. 序列化二叉树
    剑指 Offer 50. 第一个只出现一次的字符
    剑指 Offer 36. 二叉搜索树与双向链表
    剑指 Offer 35. 复杂链表的复制
    剑指 Offer 34. 二叉树中和为某一值的路径
    剑指 Offer 33. 二叉搜索树的后序遍历序列
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7596892.html
Copyright © 2020-2023  润新知