首页 > 代码库 > cogs 133. [USACO Mar08] 牛跑步 A*算法

cogs 133. [USACO Mar08] 牛跑步 A*算法

by  http://blog.csdn.net/jarily/article/details/8871968
/*
*算法引入: *在单源点最短路径问题中,实际运用时还需知道最短路径外,次短路或者第三短路; *即要知道多条最短路,并排出其长度增加的顺序,即为K最短路问题; * *算法思想: *单源点最短路径+高级搜索A*; *A*算法结合了启发式方法和形式化方法; *启发式方法通过充分利用图给出的信息来动态地做出决定而使搜索次数大大降低; *形式化方法不利用图给出的信息,而仅通过数学的形式分析; * *算法通过一个估价函数f(h)来估计图中的当前点p到终点的距离,并由此决定它的搜索方向; *当这条路径失败时,它会尝试其他路径; *对于A*,估价函数=当前值+当前位置到终点的距离,即f(p)=g(p)+h(p),每次扩展估价函数值最小的一个; * *对于K短路算法来说,g(p)为当前从s到p所走的路径的长度;h(p)为点p到t的最短路的长度; *f(p)的意义为从s按照当前路径走到p后再走到终点t一共至少要走多远; * *为了加速计算,h(p)需要在A*搜索之前进行预处理,只要将原图的所有边反向,再从终点t做一次单源点最短路径就能得到每个点的h(p)了; * *算法步骤: *(1),将有向图的所有边反向,以原终点t为源点,求解t到所有点的最短距离; *(2),新建一个优先队列,将源点s加入到队列中; *(3),从优先级队列中弹出f(p)最小的点p,如果点p就是t,则计算t出队的次数; *如果当前为t的第k次出队,则当前路径的长度就是s到t的第k短路的长度,算法结束; *否则遍历与p相连的所有的边,将扩展出的到p的邻接点信息加入到优先级队列; * *算法测试: *http://www.cogs.pro/cogs/problem/problem.php?pid=133 * *题目大意: *求从s到t的第k短路的长度; */

133. [USACO Mar08] 牛跑步

★★★   输入文件:cowjog.in   输出文件:cowjog.out   简单对比
时间限制:1 s   内存限制:128 MB

Bessie准备用从牛棚跑到池塘的方法来锻炼. 但是因为她懒,她只准备沿着下坡的路跑到池塘,然后走回牛棚.

Bessie也不想跑得太远,所以她想走最短的路经. 农场上一共有M(1<=M<=10,000)条路,每条路连接两个用1..N(1<=N<=1000)标号的地点. 更方便的是,如果X>Y,则地点X的高度大于地点Y的高度. 地点NBessie的牛棚;地点1是池塘.

很快, Bessie厌倦了一直走同一条路.所以她想走不同的路,更明确地讲,她想找出K(1<=K<=100)条不同的路经.为了避免过度劳累,她想使这K条路径为最短的K条路径.

请帮助Bessie找出这K条最短路经的长度.你的程序需要读入农场的地图, 一些从XiYi的路径和它们的长度(Xi,Yi,Di). 所有(Xi,Yi,Di)满足(1<=Yi<Xi;Yi<Xi<=N,1<=Di<=1,000,000).

题目名称: cowjog

输入格式:

  • 1行: 3个数: N,M,K
  • 2..M+1行: 第 i+1行包含3个数 Xi,Yi,Di, 表示一条下坡的路.

样例输入 (cowjog.in):

5 8 7
5 4 1
5 3 1
5 2 1
5 1 1
4 3 4
3 1 1
3 2 1
2 1 1

输出格式:

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

样例输出 (cowjog.out):

1
2
2
3
6
7
-1

输出解释:

路径分别为(5?1),(5?3?1),(5?2?1),(5?3?2?1),(5?4?3?1),(5?4?3?2?1)

代码:

/*
    k短路:
    建立反向图,计算终点到起点的单源最短路,最后A*求解最短路 
    A*算法:
    新建一个优先队列,将源点s加入到队列中; 
    从优先级队列中弹出估值函数f()最小的点p,如果点p就是t,则计算t出队的次数;
    f(n)=g(n)+h(n)  g(n) 表示走到当前点的路程  
    h(n) 表示当前位置到终点的距离(在反向跑时已经计算出) 
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>

using namespace std;
const int N=10010;
const int INF=9999999;

int head[N],head2[N],disf[N],ans[N];
int now1=1,now2=1,n,m,k,x,y,z,js;
bool vis[N];
struct zheng{
    int u,v,w,nxt;
}Z[N];
struct fang{
    int u,v,w,nxt;
}F[N];
struct node{
    int start,wei,will;
}now,nxt,topp;

inline int read()  
{  
    int x=0,f=1;char ch=getchar();  
    while(ch<0 || ch>9) {if(ch==-) f=-1;ch=getchar();}  
    while(ch>=0 && ch<=9) {x=(x<<1)+(x<<3)+ch-0;ch=getchar();}  
    return x*f;   
} 

inline void add(int u,int v,int w)
{Z[now1].v=v;Z[now1].w=w;Z[now1].nxt=head[u];head[u]=now1++;}

inline void add2(int u,int v,int w)
{F[now2].v=v;F[now2].w=w;F[now2].nxt=head2[u];head2[u]=now2++;}

bool operator < (node a,node b)
{return a.will>b.will;}

inline void spfa(int start)
{
    for(int i=1;i<=n;i++)
        disf[i]=INF;
    disf[start]=0;vis[start]=1;
    queue<int>q;
    q.push(start);
    while(!q.empty())
    {
        int topp=q.front();
        q.pop();
        vis[topp]=0;
        for(int i=head2[topp];~i;i=F[i].nxt)
            if(disf[F[i].v]>disf[topp]+F[i].w)
            {
                disf[F[i].v]=disf[topp]+F[i].w;
                if(!vis[F[i].v])
                    vis[F[i].v]=1,
                    q.push(F[i].v);
            }
    }
}

inline void Astart(int start,int endd)
{
    if(disf[start]==INF||start==endd)return ;
    priority_queue<node>q;
    now.start=start;now.wei=0;now.will=disf[start];
    q.push(now);
    while(!q.empty())
    {
        topp=q.top();
        q.pop();
        if(topp.start==endd)
        {
            ans[++js]=topp.wei;
            if(js==k)return ;
        }
        for(int i=head[topp.start];~i;i=Z[i].nxt)
        {
            nxt.start=Z[i].v;nxt.wei=topp.wei+Z[i].w;
            nxt.will=nxt.wei+disf[Z[i].v];
            q.push(nxt);
        }
    }
}

int main()
{
    freopen("cowjog.in","r",stdin);
    freopen("cowjog.out","w",stdout);
    n=read();m=read();k=read(); 
    for(int i=1;i<=n;i++)head[i]=head2[i]=-1;
    for(int i=1;i<=m;i++) x=read(),y=read(),z=read(),add(x,y,z),add2(y,x,z);
    spfa(1);//反向边的最短路 
    Astart(n,1);
    for(int i=1;i<=js;i++)printf("%d\n",ans[i]);
    for(int i=js+1;i<=k;i++)printf("-1\n");
    return 0;
}
/*
5 8 7
5 4 1
5 3 1
5 2 1
5 1 1
4 3 4
3 1 1
3 2 1
2 1 1
*/

 

cogs 133. [USACO Mar08] 牛跑步 A*算法