POJ--2449--Remmarguts' Date【dijkstra_heap+A*】第K短路

链接:http://poj.org/problem?id=2449

题意:告诉你有n个顶点,m条边。并把这些边的信息告诉你:起点、终点、权值。再告诉你s、t、k。需求出s到t的第k短路,没有则输出-1。

第K短路裸题,A*算法没接触过。參考了这篇博客:http://www.cnblogs.com/n-u-l-l/archive/2012/07/29/2614194.html

下面大体字摘自这篇博文,讲的非常清楚:

对于第k短路,能够想到的一个比較朴素的算法就是广度优先搜索,使用优先队列从源点s进行广搜,当第k次搜索到终点t时,所得长度即所求可是这样的方法在执行过程中会产生特别多的状态。当图比較简单、k比較小时,能够一试,可是当k较大或者图中点数较多时,会面临爆栈的危急。

眼下使用比較多的算法是单源最短路配合A*。

A*是搜索中比較高级的方式,A*算法结合了启示式方法(这样的方法通过充分利用图给出的信息来动态的作出决定而使搜索次数大大减少)和形式化方法(这样的方法不利用图给出的信息,而仅通过数学的形式分析,如Dijkstra算法)。

它通过一个估价函数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)须要在搜索之前进行预处理,仅仅要将原图的全部边反向,再从终点t做一次单源最短路就可以得到h(p)。单源最短路求法有Dijkstra。Bellman-Ford,SPFA等。

  详细步骤:

  这里我们使用链式前向星来存储如图。因为须要预处理全部点到终点的最短路,就须要将图G中全部边反向得到图G‘,再从终点t做一次单源最短路,所以实际上就是两张图。

  (1)将有向图的全部边反向(无向图能够省略此步),以原图终点t为源点做一次单源最短路,结果记入数组dis[i]中,dis[i]即为原图中点i到点t的最短距离。

这里的dis[i]即上述的h(p);

  (2)新建一个优先队列,将源点s增加到队列中;

  (3)从优先队列中弹出f(p)最小的点p(这里假设存在f(p)相等的点,则弹出g(p)最小的点),假设点p就是终点t,则计算t出队列的次数,假设当前为t的第k次出队,则当前路径长度就是s到t的第k短路,算法结束;否则遍历与p相连的全部的边。将扩展出的到p的邻接点信息增加到优先队列。

  值得注意的是,当s==t时须要计算(k+1)短路。由于s到t这条距离为0的路不能算在这k短路中,这时仅仅需将k自增1后再求第k短路就可以。

这道题比較坑的地方就是上面说的 s==t时须要计算(k+1)短路。m==0时也即s==t时,k+1短路不存在。应输出-1,还有就是dist[s]。=INF时,尽管A*能找到最短路。但假设k较大,不一定存在第k短路,所以应当有个标记,我忘记加标记多WA了一发

#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 100100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define seed 131
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

struct NODE{
    int u;
    int f,g;
    bool operator < (const NODE &t) const{
        if(t.f==f)  return t.g > g;
        return t.f < f;
    }
};
struct EDGE{
    int u,w,next;
};
struct NODE2{
    int u,dis;
    bool operator < (const NODE2 &t) const{
        return t.dis < dis;
    }
};
EDGE edge[MAXN],redge[MAXN];
int head[1010],rhead[1010],vis[1010],dist[1010];
int n,m,cnt,rcnt,ans,flag;
void add_edge(int a,int b,int c){
    edge[cnt].u = b;
    edge[cnt].w = c;
    edge[cnt].next = head[a];
    head[a] = cnt++;
    redge[rcnt].u = a;
    redge[rcnt].w = c;
    redge[rcnt].next = rhead[b];
    rhead[b] = rcnt++;
}
void dijkstra_heap(int v){
    NODE2 t1,t2;
    int i,j;
    for(i=1;i<=n;i++)   dist[i] = INF;
    dist[v] = 0;
    t1.u = v;
    t1.dis = 0;
    priority_queue<NODE2>q;
    q.push(t1);
    while(!q.empty()){
        t1 = q.top();
        q.pop();
        if(vis[t1.u])   continue;
        vis[t1.u] = 1;
        for(i=rhead[t1.u];i!=-1;i=redge[i].next){
            int x = redge[i].w;
            if(dist[t1.u]+x<dist[redge[i].u]){
                dist[redge[i].u] = x + dist[t1.u];
                t2.dis = dist[redge[i].u];
                t2.u = redge[i].u;
                q.push(t2);
            }
        }
    }
}
void Astar(int s,int t,int k){
    int i,j=0;
    NODE t1,t2;
    priority_queue<NODE>q;
    t1.u = s;
    t1.g = 0;
    t1.f = t1.g + dist[s];
    q.push(t1);
    while(!q.empty()){
        t1 = q.top();
        q.pop();
        if(t1.u==t) j++;
        if(j==k){
            ans = t1.f;
            flag = 1;       //没加标记,WA出翔
            return ;
        }
        for(i=head[t1.u];i!=-1;i=edge[i].next){
            t2.u = edge[i].u;
            t2.g = t1.g + edge[i].w;
            t2.f = t2.g + dist[t2.u];
            q.push(t2);
        }
    }
}
int main(){
    int i,j;
    int s,t,k;
    int a,b,c;
    while(scanf("%d%d",&n,&m)!=EOF){
        memset(head,-1,sizeof(head));
        memset(rhead,-1,sizeof(rhead));
        memset(vis,0,sizeof(vis));
        cnt = rcnt = 0;
        ans = 0;
        flag = 0;
        for(i=0;i<m;i++){
            scanf("%d%d%d",&a,&b,&c);
            add_edge(a,b,c);
        }
        scanf("%d%d%d",&s,&t,&k);
        if(s==t)    k++;
        dijkstra_heap(t);
        if(dist[s]==INF&&m==0){
            puts("-1");
            continue;
        }
        Astar(s,t,k);
        if(!flag)    puts("-1");
        else    printf("%d\n",ans);
    }
    return 0;
}

POJ--2449--Remmarguts' Date【dijkstra_heap+A*】第K短路

时间: 2024-10-13 00:25:33

POJ--2449--Remmarguts&#39; Date【dijkstra_heap+A*】第K短路的相关文章

poj 2449 Remmarguts&amp;#39; Date 【SPFA+Astar】【古典】

称号:poj 2449 Remmarguts' Date 意甲冠军:给定一个图,乞讨k短路. 算法:SPFA求最短路 + AStar 以下引用大牛的分析: 首先,为了说话方便,列出一些术语: 在启示式搜索中,对于每一个状态 x.启示函数 f(x) 一般是这种形式: f(x) = g(x) + h(x) 当中 g(x) 是从初始状态走到 x 所花的代价:h(x) 是从 x 走到目标状态所须要的代价的预计值. 相对于 h(x).另一个概念叫 h*(x),表示从 x 走到目标状态所须要的实际最小代价(

(最短路+A*搜索)POJ 2449 - Remmarguts&#39; Date

题意: 给一个DAG,要求s到t的第K短路,很经典的问题. 分析: 我们可以看到k<=1000,这个值不是很大,我可以想到直接bfs走遍所有情况,最多也就有1000中情况,但是1000个点显然会M. 既然是要求k短路,也就是说最终计算出来的到达t的花费必然是递增的,也就是说我们在搜索的时候肯定要用到优先队列. 这时应该很明显了,必然需要A*搜索,但是A*的预估函数依然是个问题,我想了很久没有想到,后来偶然在一本书上发现了这题. 书上的处理是用dijsktra预处理每点到t的最短路,就是每个状态到

图论(A*算法,K短路) :POJ 2449 Remmarguts&#39; Date

Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 25216   Accepted: 6882 Description "Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. Softly touching his little ducks' head, h

POJ 2449 Remmarguts&#39; Date

Remmarguts' Date Time Limit: 4000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 244964-bit integer IO format: %lld      Java class name: Main "Good man never makes girls wait or breaks an appointment!" said the mandari

POJ——2449 Remmarguts&#39; Date

Description "Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. Softly touching his little ducks' head, he told them a story. "Prince Remmarguts lives in his kingdom UDF – United Delta of Freedom. One

poj 2449 Remmarguts&#39; Date k短路

/*poj 2449 k短路 A* 估价函数是 s到i的距离+i到t的距离 */ #include<cstdio> #include<queue> #include<vector> #define inf 1e7 #define maxn 100010 using namespace std; int n,m,S,T,K,num1,num2,head1[maxn],head2[maxn],dis[maxn]; int q[maxn],hea,tai,f[maxn],cn

POJ 2449 Remmarguts&#39; Date (第k短路 A*搜索算法模板)

Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 22412   Accepted: 6085 Description "Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. Softly touching his little ducks' head, h

POJ 2449 Remmarguts&#39; Date ( Dijkstra + A* 求解第K短路 )

#include <iostream> #include <cstring> #include <queue> #include <fstream> using namespace std; #define E 100005 #define V 1005 #define INF 1 << 30 int heads[V], r_heads[V]; int dists[V]; bool visits[V]; int nEdgeNum, nNodeNu

poj 2449 Remmarguts&#39; Date(K短路,A*算法)

http://poj.org/problem?id=2449 大致题意:给出一个有向图,求从起点到终点的第K短路. K短路与A*算法详解  学长的博客... 算法过程 #include <stdio.h> #include <iostream> #include <algorithm> #include <set> #include <map> #include <vector> #include <math.h> #in

poj 2449 Remmarguts&#39; Date A*+spfa求第k短路

题意: 经典的第k短路,A*算法的经典应用之一. 分析: A*,已走的路程g+到终点的最短距离为启发函数,搜索过程中不判重,第k次到t节点时就求出了第k短路. 代码: //poj 2449 //sep9 #include <iostream> #include <queue> using namespace std; const int maxN=1024; const int maxM=100024; int n,m,s,t,k,e,ne; int head[maxN],nhea