[Usaco2008 Mar]牛跑步

题目描述

BESSIE准备用从牛棚跑到池塘的方法来锻炼. 但是因为她懒,她只准备沿着下坡的路跑到池塘, 然后走回牛棚. BESSIE也不想跑得太远,所以她想走最短的路经. 农场上一共有M (1 <= M <= 10,000)条路, 每条路连接两个用1..N(1 <= N <= 1000)标号的地点. 更方便的是,如果X>Y,则地点X的高度大于地点Y的高度. 地点N是BESSIE的牛棚;地点1是池塘. 很快, BESSIE厌倦了一直走同一条路.所以她想走不同的路,更明确地讲,她想找出K (1 <= K <= 100)条不同的路经.为了避免过度劳累,她想使这K条路经为最短的K条路经. 请帮助BESSIE找出这K条最短路经的长度.你的程序需要读入农场的地图, 一些从X_i到Y_i 的路经和它们的长度(X_i, Y_i, D_i). 所有(X_i, Y_i, D_i)满足(1 <= Y_i < X_i; Y_i < X_i <= N, 1 <= D_i <= 1,000,000).

输入格式

第1行: 3个数: N, M, 和K

第 2..M+1行: 第 i+1 行包含3个数 X_i, Y_i, 和 D_i, 表示一条下坡的路.

输出格式

第1..K行: 第i行包含第i最短路经的长度,或-1如果这样的路经不存在.如果多条路经有同样的长度,请注意将这些长度逐一列出.


题意就是,求出给定图的前k短的n到1的路径,题目中的高度关系指明了图是有向的。

所以我们可以用A*来求k短路。

设计估价函数f。秉持f永远不大于真实值的原则,我们可以建个反图,把所有点到终点的最短路作为估计值,这样无论k等于多少时真实值都不会小于估计值。

然后跑A*,每次终点被取出时就输出此时的距离。注意如果取出次数不足k要用-1补足。

时间复杂度上限为O(K * (N+M)log(N+M)),但由于启发式,远远达不到这个程度。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define maxn 1001
#define maxm 100001
using namespace std;
   
struct graph{
    struct edge{
        int to,dis,next;
        edge(){}
        edge(const int &_to,const int &_dis,const int &_next){ to=_to,dis=_dis,next=_next; }
    }e[maxm];
    int head[maxn],k;
    inline void init(){ memset(head,-1,sizeof head); }
    inline void add(const int &u,const int &v,const int &w){ e[k]=edge(v,w,head[u]); head[u]=k++; }
}a,b;
   
int f[maxn];
bool vis[maxn];
int n,m,s,K;
   
struct set_elmt{
    int id,dis;
    set_elmt(){}
    set_elmt(const int &_dis,const int &_id){ id=_id,dis=_dis; }
    bool operator<(const set_elmt &x)const{ return dis>x.dis; }
};//Dijkstra的优先级
   
struct node{
    int id,dis;
    node(){}
    node(const int &_dis,const int &_id){ id=_id,dis=_dis; }
    bool operator<(const node &x)const{ return dis+f[id]>x.dis+f[x.id]; }
};//A*的优先级
   
inline int read(){
    register int x(0),f(1); register char c(getchar());
    while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
    while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
   
inline void dijkstra(){
    memset(f,0x3f,sizeof f);
    priority_queue<set_elmt> q;
    q.push(set_elmt(0,1)),f[1]=0;
       
    while(q.size()){
        int u=q.top().id; q.pop();
        if(vis[u]) continue; vis[u]=true;
        for(register int i=b.head[u];~i;i=b.e[i].next){
            int v=b.e[i].to;
            if(f[v]>f[u]+b.e[i].dis) f[v]=f[u]+b.e[i].dis,q.push(set_elmt(f[v],v));
        }
    }
}
   
inline void astar(){
    priority_queue<node> q;
    q.push(node(0,n));
    while(q.size()){
        int u=q.top().id,w=q.top().dis; q.pop();
        if(u==1){ printf("%d\n",w); if(--K==0) return; }
        for(register int i=a.head[u];~i;i=a.e[i].next){
            int v=a.e[i].to;
            q.push(node(w+a.e[i].dis,v));
        }
    }
    while(K--) puts("-1");
}
   
int main(){
    a.init(),b.init();
    n=read(),m=read(),K=read();
    for(register int i=1;i<=m;i++){
        int u=read(),v=read(),w=read();
        a.add(u,v,w),b.add(v,u,w);//b为反图
    }
    dijkstra(),astar();
    return 0;
}
posted @ 2019-06-04 19:57  修电缆的建筑工  阅读(383)  评论(0编辑  收藏  举报