poj 2449 求第k最短路 A* + SPFA

这题要求出第k短路的长度

对于第k短路 , 我们一般都是用A* + SPFA算法 ,
首先 , 我们先求求出所有点到终点的最短路径长度 , 并把这些长度 , 最为估价函数的一部分
然后,我们再用bfs、优先队列、加上A*算法思想 , 就能得到第k短路的长度
对于第k短路 , 我们只需要在优先队列中第k次遍历到终点时 , 那么这个路径长度就是第k短路的长度,因为我们在使用优先队列时 , 最先出队的 , 肯定是状态最优的 , 因此第k次出队列的, 那么肯定是第k优的。

有一个特殊情况 , 当终点和起点相同时 , 我们应该求到第k+1短路 , 因此当起点和终点一样时 , 最优的(或则第一次出队的)肯定是长度为0的点 , 所以这个状态是不能算入进去的 , 因为求两点的路径长度,肯定是要经过一些其他点的

关于A*算法
      我们认为不应该把A*认为是一种算法, 只能把它看做是一种思想 , 对于搜索时的优先思想 , 就像搜索时使用优先队列一样 , 这也能看做是一种A* , 因此A*只是一种思想,并且这种思想的不确定性非常大 。

代码:
//A* + SPFA 求第k短路径长度
#include
#include
#include
#include
#include
using namespace std;

#define INF 0xfffffff
#define maxn 1010

struct node
{
      int to;
      int w;
};

struct node1
{
      int to;
      int g , f;
      bool operator <(const node1 &r)  const
      {
            if(r.f == f)  return r.g < g;
            return r.f < f;
      }
};

vectorgrap[maxn];
vectorfgrap[maxn];
int dist[maxn];
int n , m , k , sx , ty;

void init()
{
      for(int i = 1; i <= n; i++)
      {
            grap[i].clear();
            fgrap[i].clear();
      }
}

void SPFA()
{
      int pre[maxn] , i , y;

      memset(pre , 0 , sizeof(pre));

      queueq;
      q.push(ty);

      for(i = 1; i <= n; i++)
            dist[i] = INF;
      dist[ty] = 0;

      while(!q.empty())
      {
            int x = q.front();  q.pop();
            pre[x] = 0;

            for(i = 0; i < fgrap[x].size(); i++)
            {
                  y = fgrap[x][i].to;
                  if(dist[y] > dist[x]+fgrap[x][i].w)
                  {
                        dist[y] = dist[x]+fgrap[x][i].w;
                        if(!pre[y])  q.push(y) , pre[y] = 1;
                  }
            }
      }
}

int a_star()
{
      int cnt = 0 , x , i;
      node1 u , v;
      priority_queueq;

      if(dist[sx] == INF)  return -1;
      if(sx == ty)  k += 1;

      u.to = sx;  u.g = 0; u.f = u.g+dist[sx];
      q.push(u);

      while(!q.empty())
      {
            u = q.top();  q.pop();
            x = u.to;

            if(x == ty)  cnt += 1;

            if(cnt == k)  return u.g;

            for(i = 0; i < grap[x].size(); i++)
            {
                  v.to = grap[x][i].to;
                  v.g = u.g+grap[x][i].w;
                  v.f = v.g + dist[v.to];
                  q.push(v);
            }
      }

      return -1;
}

int main()
{
      while(scanf("%d %d" , &n , &m) != EOF)
      {
            init();
           
            int i , x , y , z;
            node u;
            for(i = 0; i < m; i++)
            {
                  scanf("%d %d %d" , &x , &y , &z);
                  u.to = y;  u.w = z;
                  grap[x].push_back(u);
                  u.to = x;
                  fgrap[y].push_back(u);
            }
            scanf("%d %d %d" , &sx , &ty , &k);
            SPFA();

            x = a_star();

            cout<<x<<endl;

      }
      return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值