zoukankan      html  css  js  c++  java
  • 【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短路。

  • 相关阅读:
    vfork与fork的区别
    常见的六种设计模式以及应用场景
    Java中常见的集合类比较
    排序——总结
    排序——交换排序
    排序——选择排序
    排序——归并排序
    排序——基数排序
    排序——插入排序
    设计模式
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7596892.html
Copyright © 2011-2022 走看看