poj2449 第k短路 (單源最短路徑+A*)

題目鏈接:http://poj.org/problem?id=2449

題意
題目的意思很明確,就是讓你求s到t的第k短路。不過有一個trick點就是必須要經過路徑,也就是說如果s=t的話,在算第k短路時不能算s到t爲0這條路。

題解
基本就是裸的第k短路,而第k短路是單源最短路和A*算法的組合。對於A*算法,都知道f(n)=g(n)+h(n),這裏h(n)爲啓發式函數。我們令這裏的g(n)爲從源點s到n所經過的路徑,h(n)爲把所有邊反向後從終點t到n的最短路徑dist[n]。即估值=源點到當前點的距離+當前點到終點的最短距離。這時我們建一個優先隊列,每次彈出估值f()最小的點,如果彈出的點是t就計算t出隊的次數,如果次數等於k,那麼到當前點的距離g()即爲答案,否者就拓展與當前點相連的邊。

#include <cstdio>
#include <cstdlib>
#include <queue>
#include <iostream>
#include <cstring>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;

const int maxn = 1e3+5;
const int maxm = 1e5+5;
int n,m,s,t,k,ans;
//前向星儲存邊
int head[maxn],A_head[maxn],cnt1,cnt2;
//dist[]儲存終點到其它點的最短路
int dist[maxn];

struct Edge{
    int to,w,next;
}edge1[maxm],edge2[maxm];

struct A_Node{
    int p,g,h;
    bool operator < (A_Node tmp) const
    {
        return tmp.g+tmp.h < g+h;
    }
};

typedef pair<int,int> P;

void init()
{
    memset(head,-1,sizeof(head));
    memset(A_head,-1,sizeof(A_head));
    memset(dist,INF,sizeof(dist));
    cnt1=cnt2=0;
}

void add_edge(int from,int to,int w,bool flag)
{
    if(flag)
    {
        edge1[cnt1].to = to;
        edge1[cnt1].w = w;
        edge1[cnt1].next = head[from];
        head[from] = cnt1++;
    }
    else
    {
        edge2[cnt2].to = to;
        edge2[cnt2].w = w;
        edge2[cnt2].next = A_head[from];
        A_head[from] = cnt2++;
    }
}

void Dijkstra() //優先隊列優化的Dijkstra求終點到其它點的最短路
{
    priority_queue<P,vector<P>,greater<P> >pq;
    P p;
    dist[t] = 0;
    pq.push(P(0,t));
    while(!pq.empty())
    {
        p = pq.top(),pq.pop();
        int u = p.second;
        for(int i=head[u];i!=-1;i=edge1[i].next)
        {
            if(dist[edge1[i].to] > dist[u] + edge1[i].w)
            {
                dist[edge1[i].to] = dist[u]+edge1[i].w;
                pq.push(P(dist[edge1[i].to],edge1[i].to));
            }
        }
    }
}

void A_stra()
{
    A_Node cur,next;
    int num=0;
    priority_queue<A_Node>pq;
    //源點爲終點,不去掉爲0的路徑就相當於求第k+1短路
    if(s==t) k++;  
    if(dist[s]==INF)
    {
        ans=-1;
        return;
    }
    cur.p = s;
    cur.g = 0;
    cur.h = dist[s];
    pq.push(cur);
    while(!pq.empty())
    {
        cur = pq.top(),pq.pop();
        if(cur.p==t) num++;
        if(num==k)
        {
            ans = cur.g;
            return;
        }
        for(int i=A_head[cur.p];i!=-1;i=edge2[i].next)
        {
            next.p = edge2[i].to;
            next.g = cur.g+edge2[i].w;
            next.h = dist[next.p];
            pq.push(next);
        }
    }
    ans = -1;
    return;
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        int u,v,w;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add_edge(v,u,w,true);
            add_edge(u,v,w,false);
        }
        scanf("%d%d%d",&s,&t,&k);
        Dijkstra();
        A_stra();
        printf("%d\n",ans);
    }
    return 0;
}
發佈了82 篇原創文章 · 獲贊 37 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章