POJ 2449 Remmarguts' Date K最短路问题(单源点最短路径+A*算法)

来源:互联网 发布:微博桌面2015网络异常 编辑:程序博客网 时间:2024/05/17 02:47

算法解释感谢Jarily  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的邻接点信息加入到优先级队列; * *算法测试: *PKU2449(Remmarguts' Date) * *题目大意: *求从s到t的第k短路的长度; */#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#include <vector>using namespace std;#define N 1010#define M 100010#define INF 1e9typedef int type;type dis[N];int out[N];bool visit[N];struct Node{    int pos;    type g,f; // g(i) 为从start到i目前已走的距离  ,  f(i)=g(i)+dis(i)    friend bool operator<(Node a,Node b)    {        return a.f>b.f;    }};struct{    int to,next;    type c;}edge[M<<1];int ip;int head1[N],head2[N];void addedge1(int u,int v,type c){    edge[ip].to=v; edge[ip].c=c; edge[ip].next=head1[u]; head1[u]=ip++;}void addedge2(int u,int v,type c){    edge[ip].to=v; edge[ip].c=c; edge[ip].next=head2[u]; head2[u]=ip++;}bool spfa(int start,int end,int n) //以end为起点求i到end的最短路{    queue<int>q;    memset(out,0,sizeof(out));    memset(visit,0,sizeof(visit));    for(int i=0;i<=n;i++) dis[i]=INF;    q.push(start); visit[start]=1; dis[start]=0;    int top;    while(!q.empty())    {        top=q.front(); q.pop(); visit[top]=0; out[top]++;        if(out[top]>n) return 0;        for(int p=head2[top];p!=-1;p=edge[p].next)        {            if(dis[ edge[p].to ] > dis[top] + edge[p].c )            {                dis[edge[p].to]=dis[top]+edge[p].c;                if(!visit[edge[p].to])                {                    visit[edge[p].to]=1; q.push(edge[p].to);                }            }        }    }    if(dis[end]==INF) return 0;    return 1;}int K_load(int start,int end,int k){    Node top,temp;    priority_queue<Node>q;    int time=0;    top.pos=start; top.g=0; top.f=dis[start]; q.push(top);    while(!q.empty())    {        top=q.top(); q.pop();        if(top.pos==end) time++;        if(time==k) return top.f;        for(int p=head1[top.pos];p!=-1;p=edge[p].next)        {            temp.pos=edge[p].to;            temp.g=top.g+edge[p].c;            temp.f=temp.g+dis[edge[p].to];            q.push(temp);        }    }    return -1;}int solve(int start,int end,int k,int n){    if(!spfa(end,start,n)) return -1;    return K_load(start,end,k);}int main(){    int n,m;    int x,y;    int start,end,k;    type c;    while(cin>>n>>m)    {        ip=0;        memset(head1,-1,sizeof(head1));        memset(head2,-1,sizeof(head2));        while(m--)        {            scanf("%d%d%d",&x,&y,&c);  //c输入类型需要修改            addedge1(x,y,c);            addedge2(y,x,c);  //建反向边        }        cin>>start>>end>>k;        if(start==end) k++;   //这题需要特殊处理        cout<<solve(start,end,k,n)<<endl;    }    return 0;}