POJ2449

//题目类型:求K最短路
//算法实现:Dijkstra+A*(启发式搜索)
//首先求出其他点到des的最短距离,然后用基于BFS的优先队列A*算法求,f(i)=g(i)+h(i)  其中h(i)表示i到des的最短路,g(i)表示从src到i的
//路径长度每次取出f(i)值最小的,当第k次取出t时即求出第k短路
#include <iostream>
#include <queue>
//#include <conio.h>
using namespace std;
#define marray 100001
#define narray 1001
const int maxData = 0x7fffffff;
typedef struct edge
{
    int v;
    int w;
    edge *next;
}edge;
edge *adj[narray],*readj[narray],edges[marray],reedges[marray]; //正向邻接表指针,逆向邻接表指针,正向边,逆向边
typedef struct dijedge                  //Dijstra求最短路时优先级队列
{
    int v;
    int w;
    bool operator <(const dijedge & a) const
    {
         return w>a.w;
    }
}dijedge;
int edgenum,reedgenum;
int n,m;
int d[narray];
bool final[narray];
int cnt[narray];                  //A*搜索时记录入队列次数
int src,des,k;
typedef struct aedge                //A*搜索时的优先级队列
{
    int v;
    int w;
    bool operator<(const aedge &a)const    //f(n)=d[i]+g[i]
    {
         return w+d[v]>a.w+d[a.v];
    }  
}aedge;
void addEdge(int start,int end,int w)
{
     edge *ptr = &edges[edgenum++];
     ptr->v = end;
     ptr->w = w;
     ptr->next = adj[start];
     adj[start] = ptr;
}
void addReEdge(int start,int end,int w)
{
     edge *ptr =&reedges[reedgenum++];
     ptr->v = end;
     ptr->w = w;
     ptr->next = readj[start];
     readj[start] = ptr;
}
void Dij(int src)
{
     int i,j;
     dijedge tempedge;
     priority_queue<dijedge> myqueue;
     memset(final,0,sizeof(final));
     for(i=1;i<=n;++i) d[i] = maxData;
     d[src] = 0;
     final[src] = true;
     tempedge.v=src;
     tempedge.w=0;
     myqueue.push(tempedge);
     while(!myqueue.empty())
     {
         int frontv = myqueue.top().v;
         int frontw = myqueue.top().w;
         myqueue.pop();
         final[frontv] = true;
         for(edge *p = readj[frontv];p;p=p->next)
         {
             int tempv= p->v;
             int tempw= p->w;
             if(!final[tempv] && d[tempv]>d[frontv]+tempw)
             {
                  d[tempv] = d[frontv]+tempw;
                  tempedge.v = tempv;
                  tempedge.w = d[tempv];
                  myqueue.push(tempedge);
             }            
         }
     }
}
int a_star()
{
     aedge tempaedge;
     priority_queue<aedge> myqueue;
     memset(cnt,0,sizeof(cnt));    //记录顶点的入队列次数
     if(d[src]==maxData) return -1;
     if(src==des) k++;             //考虑终点和源点相同的情况,针对题目要求
     tempaedge.v = src;
     tempaedge.w = 0;
     myqueue.push(tempaedge);
     while(!myqueue.empty())
     {
         int frontv = myqueue.top().v;
         int frontw = myqueue.top().w;
         myqueue.pop();
         cnt[frontv]++;
         if(cnt[des]==k) return frontw;     //终点入队列k次,说明找到了K最短路
         if(cnt[frontv]>k) continue;       
         for(edge *p = adj[frontv];p;p=p->next)
         {
             tempaedge.v = p->v;
             tempaedge.w = frontw +  p->w;
             myqueue.push(tempaedge);
         }
     }
     return -1;
}
int main()
{
    //freopen("1.txt","r",stdin);
    int i,j;
    int start,end,value;
    while(scanf("%d%d",&n,&m)!=-1)
    {
        edgenum = 0;
        reedgenum = 0;
        for(i=1;i<=n;++i)
        {
            adj[i] = NULL;
            readj[i] = NULL;
        }
        for(i=1;i<=m;++i)
        {
            scanf("%d%d%d",&start,&end,&value);
            addEdge(start,end,value);
            addReEdge(end,start,value);
        }
        scanf("%d%d%d",&src,&des,&k);
        Dij(des);                    //求出终点到其他点的最短路(利用逆向邻接表实现)
        printf("%d\n",a_star());
    }
    //getch();
    return 0;
}

posted @ 2010-06-05 14:52  北海小龙  阅读(1105)  评论(0编辑  收藏  举报