【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短路。

原文地址:https://www.cnblogs.com/onioncyc/p/7596892.html