Fork me on GitHub

POJ 2449 Remmarguts' Date --K短路

题意就是要求第K短的路的长度(S->T)。

对于K短路,朴素想法是bfs,使用优先队列从源点s进行bfs,当第K次遍历到T的时候,就是K短路的长度。

但是这种方法效率太低,会扩展出很多状态,所以考虑用启发式搜索A*算法。

估价函数 = 当前值 + 当前位置到终点的距离,即F(p) = G(p) + H(p)。 

G(p): 当前从S到p所走的路径距离

H(p): 当前点p到终点T的最短路径距离   ---可以先将整个图边方向取反然后以T为源点求个最短路,用SPFA提速

F(p): 从S按照当前路径走到p然后走到T一共至少走多远

所以我们结合SPFA+A*可以解决。

注意:当S==T时,需要计算第K+1短路,因为从S->T这条长度为0的路径不能算在内。

还有,SPFA处判了一下负环。SPFA算法中,如果某个点出队次数大于n,说明此处存在负环。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <functional>
#define Mod 1000000007
using namespace std;
#define N 1007

struct node
{
    int v;
    int g,f; //f = g+h
    bool operator < (const node &a)const
    {
        if(a.f == f)
            return a.g < g;
        return a.f < f;
    }
};

struct Edge
{
    int v,w,next;
}G[100*N],G2[100*N];

int head[100*N],head2[100*N];
int vis[N],dis[N];
int out[N];
int n,m,K,S,T,tot,tot2;

void addedge(Edge *G,int& tot,int *head,int u,int v,int w)
{
    G[tot].v = v;
    G[tot].w = w;
    G[tot].next = head[u];
    head[u] = tot++;
}

int SPFA(int s,int head[N],Edge G[N],int dis[N])
{
    int i;
    queue<int> que;
    for(i=0;i<=n;i++)
        dis[i] = Mod;
    memset(vis,0,sizeof(vis));
    memset(out,0,sizeof(out));
    que.push(s);
    vis[s] = 1;
    dis[s] = 0;
    while(!que.empty())
    {
        int now = que.front();
        que.pop();
        vis[now] = 0;
        out[now]++;
        if(out[now] > n)
            return 0;
        for(int k=head[now];k!=-1;k=G[k].next)
        {
            if(dis[G[k].v] > dis[now] + G[k].w)
            {
                dis[G[k].v] = dis[now] + G[k].w;
                if(!vis[G[k].v])
                {
                    vis[G[k].v] = 1;
                    que.push(G[k].v);
                }
            }
        }
    }
    return 1;
}

int A_Star(int head[N],Edge G[N],int dis[N])
{
    node tmp,now;
    int cnt = 0;
    priority_queue<node> que;
    if(S == T)
        K++;
    if(dis[S] == Mod)
        return -1;
    tmp.v = S;
    tmp.g = 0;
    tmp.f = tmp.g+dis[S];
    que.push(tmp);
    while(!que.empty())
    {
        tmp = que.top();
        que.pop();
        if(tmp.v == T)
            cnt++;
        if(cnt == K)
            return tmp.g;
        for(int i=head[tmp.v];i!=-1;i=G[i].next)
        {
            now.v = G[i].v;
            now.g = tmp.g + G[i].w;
            now.f = now.g + dis[now.v];
            que.push(now);
        }
    }
    return -1;
}

int main()
{
    int i,j,u,v,w;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(head,-1,sizeof(head));
        memset(head2,-1,sizeof(head2));
        tot = tot2 = 1;
        for(i=0;i<m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            addedge(G,tot,head,u,v,w);   //原图
            addedge(G2,tot2,head2,v,u,w);   //反图
        }
        scanf("%d%d%d",&S,&T,&K);
        if(SPFA(T,head2,G2,dis))
        {
            int k_len = A_Star(head,G,dis);
            printf("%d\n",k_len);
        }
        else
            puts("-1");
    }
    return 0;
}
View Code

 

posted @ 2014-06-10 23:50  whatbeg  阅读(234)  评论(0编辑  收藏  举报