UVA-10740 - Not the Best (K短路)

题意:求A到B的K短路!

分析:使用A*算法

 所谓K短路,就是从s到t的第K短的路,第1短就是最短路。

    如何求第K短呢?有一种简单的方法是广度优先搜索,记录t出队列的次数,当t第k次出队列时,就是第k短路了。但点数过大时,入队列的节点过多,时间和空间复杂度都较高。

    A*是在搜索中常用的优化,一种启发式搜索。简单的说,它可以用公式表示为f(n) = g(n) + h(n),其中,f(n)是从s经由节点n到t的估价函数,g(n)是在状态空间中从s到n的实际代价,h(n)是从n到t的最佳路径估计代价。在设计中,要保证h(n)<= n到t的实际代价,这一点很重要,h(n)越接近真实值,速度越快。

 由于启发函数的作用,使得计算机在进行状态转移时尽量避开不可能产生最优解的分支,而选择相对较接近最优解的路径进行搜索,降低了时间和空间复杂度。

  算法过程:

    1. 将图反向,用dijstra+heap求出t到所有点的最短距离,目的是求所有点到点t的最短路,用dis[i]表示i到t的最短路,其实这就是A*的启发函数,显然:h(n)<= n到t的实际代价。

    2. 定义估价函数。我们定义g(n)为从s到n所花费的代价,h(n)为dis[n],显然这符合A*算法的要求。

    3. 初始化状态。状态中存放当前到达的点i,fi,gi。显然,fi=gi+dis[i]。初始状态为(S,dis[S],0),存入优先级队列中。

    4. 状态转移。假设当前状态所在的点v相邻的点u,我们可以得到转换:(V,fv,gv)-->(U,fu+w[v][u],gv+w[v][u])。

    5. 终止条件。每个节点最多入队列K次,当t出队列K次时,即找到解。

// File Name: 10740.cpp
// Author: Zlbing
// Created Time: 2013/5/19 0:44:07

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define REP(i,r,n) for(int i=r;i<=n;i++)
#define RREP(i,n,r) for(int i=n;i>=r;i--)
const int MAXN=105;

struct Edge{
    int u,v,cost;
};
vector<Edge> edges;
vector<int> G[MAXN];
vector<Edge> O_edges;
vector<int> O_G[MAXN];
int S,T,K;
struct node{
    int u;
    int f,g;
    bool operator <(const node& rhs)const{
        return f>rhs.f;
    }
};
int h[MAXN];
void dij(int t)
{
    priority_queue<node> Q;
    CL(h,-1);
    Q.push((node){t,0,0});
    while(!Q.empty())
    {
        node tmp=Q.top();
        Q.pop();
        int u=tmp.u;
        int cost=tmp.f;
        if(h[u]!=-1)continue;
        h[u]=cost;
        for(int i=0;i<O_G[u].size();i++)
        {
            int mm=O_G[u][i];
            Edge e=O_edges[mm];
            tmp.u=e.v;
            tmp.f=e.cost+cost;
            Q.push(tmp);
        }
    }
}
int cnt[MAXN];
int a_star()
{
    CL(cnt,0);
    priority_queue<node> Q;
    if(h[S]==-1)return -1;
    Q.push((node){S,h[S],0});
    node t,tt;
    while(!Q.empty())
    {
        t=Q.top();
        Q.pop();
        int u=t.u;
        int f=t.f;
        int g=t.g;
        cnt[u]++;
        if(cnt[T]==K)return g;
        if(cnt[u]>K)continue;
        for(int i=0;i<G[u].size();i++)
        {
            Edge e=edges[G[u][i]];
            tt.u=e.v;
            tt.g=g+e.cost;
            tt.f=tt.g+h[tt.u];
            Q.push(tt);
        }
    }
    return -1;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)break;
        REP(i,0,n){
            G[i].clear();
            O_G[i].clear();
        }
        edges.clear();
        O_edges.clear();
        scanf("%d%d%d",&S,&T,&K);
        int a,b,c;
        REP(i,1,m)
        {
            scanf("%d%d%d",&a,&b,&c);
            edges.push_back((Edge){a,b,c});
            O_edges.push_back((Edge){b,a,c});
            int mm=edges.size();
            G[a].push_back(mm-1);
            O_G[b].push_back(mm-1);
        }
        dij(T);
        int ans=a_star();
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2013-05-19 01:24  z.arbitrary  阅读(482)  评论(0编辑  收藏  举报