【A* + dijkstraの预处理】——poj2449——第k短路问题

                                         Remmarguts' Date

Time Limit: 4000MS   Memory Limit: 65536K
Total Submissions: 26310   Accepted: 7153

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 day their neighboring country sent them Princess Uyuw on a diplomatic mission." 

"Erenow, the princess sent Remmarguts a letter, informing him that she would come to the hall and hold commercial talks with UDF if and only if the prince go and meet her via the K-th shortest path. (in fact, Uyuw does not want to come at all)" 

Being interested in the trade development and such a lovely girl, Prince Remmarguts really became enamored. He needs you - the prime minister's help! 

DETAILS: UDF's capital consists of N stations. The hall is numbered S, while the station numbered T denotes prince' current place. M muddy directed sideways connect some of the stations. Remmarguts' path to welcome the princess might include the same station twice or more than twice, even it is the station with number S or T. Different paths with same length will be considered disparate. 

Input

The first line contains two integer numbers N and M (1 <= N <= 1000, 0 <= M <= 100000). Stations are numbered from 1 to N. Each of the following M lines contains three integer numbers A, B and T (1 <= A, B <= N, 1 <= T <= 100). It shows that there is a directed sideway from A-th station to B-th station with time T. 

The last line consists of three integer numbers S, T and K (1 <= S, T <= N, 1 <= K <= 1000).

Output

A single line consisting of a single integer number: the length (time required) to welcome Princess Uyuw using the K-th shortest path. If K-th shortest path does not exist, you should output "-1" (without quotes) instead.

Sample Input

2 2
1 2 5
2 1 4
1 2 2

Sample Output

14

Source

 

题意:求从s点到t点的第k短路

 

思路:(转)

      A*就是启发是搜索..说白了就是给BFS搜索一个顺序使得搜索更加合理减少无谓的搜索..如何来确定搜索的顺序?..也就是用一个值来表示这个值为f[x]..每次搜索取f[x]最小的拓展...那么这个f[x]=h[x]+g[x]其中这个h[x]就是当前搜索时的代价..如求K段路这个就是前一个点的h[x']+边的长度...而g[x]是一个估价函数..估价函数要小于是对当前点到目标的代价的估计..这个估计必须小于等于实际值~~否则会出错...A*的关键也就是构造g[x]..

    而这里要说的求K短路一种方法..就是用BFS+A*来搜索的过程...g[x]的设定为到这个点到目标点的最短路径...显然其实小于等于实际值的...h[x]就是搜索到这个点的代价..用一个优先队列来做..每次取出h[x]+g[x]最小的点来拓展...拓展也就是通过这点来更新其能直接经过一条边到达的点..这里做好一个新点就丢进优先队列里去..反正总会从对首弹出h[x]+g[x]最小的点..可以想一下...如果当前取出的优先队列头是一个点e并且是第一次取出h..那么就找到了一条从源点到h的最短路径..这里其实很djikstra的感觉差不多..如果第二次在对头取出了e..则是找到了一条从源点到h的第二短路径..依次类推..第几次从对头弹出e..则找到了从源点到e的第几短路径..

    那要是本身就不存在K短路呢??那就是e拓展不到K但是其他点很有可能一直打圈圈无限下去...这里就要用个条件来判断一下...首先在找某个点作为优先队列头出现了几次就用了一个计数器times[]..所求的点times[e]==k就代表得到了解..如果当前想拓展的点times[]>k就没必要拓展了..因为这个点已经是求到k+1短路了..从这个点继续往下搜肯定得到的是大于等于k+1短路的路径...就像1->2有3条路..2->3有2条路..那1->3有6条路的概念差不多..没必要对其进行拓展了..

    还有一点要特别注意的就是题目要求必须要走..也就是s==e时..k++....

 

代码如下:

#include<iostream>
#include<queue>
#include<string.h>
#include<stdio.h>
using namespace std;

#define MAXN 1001

struct node
{
    //g 表示起点到当前点的距离,h表示当前点到终点的距离
    int g,h;
    int to;
    //估价函数最小优先队列——使g+h小的在队首
    bool operator < (node a) const
    {
        return a.g+a.h<g+h;
    }
};

//存两个图的链式前向星
struct egde
{
     int x,y,w;
     int next;
}line[MAXN*100],line1[MAXN*100];//建立图和反向图
int link[MAXN];
int link1[MAXN];

int n,m;
int s,e,k;
bool used[MAXN];
int g[MAXN];//终点到各点得距离

//求估价函数
//算出从终点到各点的距离
void djikstra()
{
    int i,k,p;
    memset(used,0,sizeof(used));
    memset(g,0x7f,sizeof(g));
    g[e]=0;

    for (p=1;p<=n;p++)
    {
        k=0;

        for (i=1;i<=n;i++)
        {
            if (used[i]==false && (k==0 || g[i]<g[k]))
            {
                k=i;
            }
        }

        used[k]=true;
        k=link1[k];

        while(k>0)
        {
            if (g[line1[k].y]>g[line1[k].x]+line1[k].w)
            {
                g[line1[k].y]=g[line1[k].x]+line1[k].w;
            }
            k=line1[k].next;
        }
     }
     return ;
}

//求最第k短路
int Astar()
{
    priority_queue<node> myqueue;

    int t;
    int times[MAXN];//第几次到达终点

    node h,temp;

    //初始化
    while (!myqueue.empty())
        myqueue.pop();
    memset(times,0,sizeof(times));

    h.to=s;
    h.g=0;
    h.h=0;
    myqueue.push(h);

    while (!myqueue.empty())
    {
        h=myqueue.top();
          myqueue.pop();

        times[h.to]++;

        if (times[h.to]==k && h.to==e)
            return h.h+h.g;

        //算得一条路是k+n短路
        if (times[h.to]>k)
            continue;

        t=link[h.to];
        while (t>0)//优化相连路径
        {
            temp.h=h.h+line[t].w;
            temp.g=g[line[t].y];
            temp.to=line[t].y;

            myqueue.push(temp);

            t=line[t].next;
        }
    }
    return -1;
}

int main()
{
     scanf("%d%d",&n,&m);

     memset(link,0,sizeof(link));
     memset(link1,0,sizeof(link1));

     //建图
     for (int i=1;i<=m;i++)
     {
          scanf("%d%d%d",&line[i].x,&line[i].y,&line[i].w);

          line[i].next=link[line[i].x];
          link[line[i].x]=i;

          line1[i].x=line[i].y;
          line1[i].y=line[i].x;
          line1[i].w=line[i].w;

          line1[i].next=link1[line1[i].x];
          link1[line1[i].x]=i;
     }

     scanf("%d%d%d",&s,&e,&k);

     //自己到自己也是一条路
     if (s==e)
        k++;

     djikstra();

     printf("%d\n",Astar());

     return 0;
}

 

posted @ 2016-06-25 09:52  琥珀川||雨露晨曦  阅读(145)  评论(0)    收藏  举报