zoukankan      html  css  js  c++  java
  • [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
    ",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;
    }
    
  • 相关阅读:
    搜狗输入法用户体验评价
    第二阶段团队冲刺5
    第二阶段团队冲刺4
    进度总结报告十四
    第二阶段团队冲刺3
    寻找水王-课上练习
    第二阶段团队冲刺2
    大型网站处理高并发要点技术
    php 处理上百万条的数据库如何提高处理查询速度
    php一次性大量数据入库解决方法
  • 原文地址:https://www.cnblogs.com/akura/p/10975753.html
Copyright © 2011-2022 走看看