poj2449第K短路问题(A*算法)

启发函数:f(x)=g(x)+h(x);

g(x)表示初始点到x状态的代价,h(x)表示从x的状态到目标状态的代价的估计值(并不是真实的),实际最小代价<=h(x);

起点s,终点t,x.v=s,x.len=0;然后优先队列中f(x)值最小值出队列,再根据出队列的x.v状态发展下一层。如果出队列时第一次遇到x.v==t,

就找到了s到t的最短路。...如果第k次,那就是第k短。为了加速计算,h(p)需要在A*搜索之前进行预处理,只要将原图的所有边反向,

再从终点t做一次单源点最短路径就能得到每个点的h(p)了;

其实到现在可以发现,如果g(x)为0,那么求出来的就是最短路系列,如果h(x)为0,求出来的就是BFS最少次数。

#include<stdio.h>
#include<string.h>
#include<queue>
#define INF 99999999
using namespace std;
const int maxn = 1100;
struct Enode
{
    int to;
    int val;
    int next;
}edge1[100100],edge2[100100];
struct node
{
    int to;
    int g,f;//g别的点到此状态的代价 f启发函数
    friend bool operator<(node a,node b){
        if(a.f!=b.f)
            return a.f>b.f;
        return a.g>a.g;
    }
};
int n,dis[maxn],pre1[maxn],pre2[maxn],index1,index2;
void init()
{
    index1=index2=1;
    memset(pre1,-1,sizeof(pre1));
    memset(pre2,-1,sizeof(pre2));
}
void add1(int x,int y,int z)
{
    edge1[index1].to=y;
    edge1[index1].val=z;
    edge1[index1].next=pre1[x];
    pre1[x]=index1++;
}
void add2(int x,int y,int z)
{
    edge2[index2].to=y;
    edge2[index2].val=z;
    edge2[index2].next=pre2[x];
    pre2[x]=index2++;
}
void spfa(int s)
{
    queue<int>q;
    int vis[maxn],i,j;
    for(i=0;i<=n;i++)
    {
        vis[i]=0;
        dis[i]=INF;
    }
    dis[s]=0;
    vis[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        vis[t]--;
        if(vis[t]>n)
            break;
        for(i=pre2[t];i!=-1;i=edge2[i].next)
        {
            if(dis[edge2[i].to]>dis[t]+edge2[i].val)
            {
                dis[edge2[i].to]=dis[t]+edge2[i].val;
                q.push(edge2[i].to);
            }
        }
    }
}
int A_star(int s,int t,int k)
{
    node temp;
    priority_queue<node>q;
    int cnt=0;
    if(s==t) k++;
    if(dis[s]==INF)
        return -1;
    temp.to=s;
    temp.g=0;
    temp.f=temp.g+dis[temp.to];
    q.push(temp);
    while(!q.empty())
    {
        temp=q.top();
        q.pop();
        if(temp.to==t)
        {
            cnt++;
        }
        if(cnt==k)
        {
            return temp.g;
        }
        for(int i=pre1[temp.to];i!=-1;i=edge1[i].next)
        {
            node tt;
            tt.to=edge1[i].to;
            tt.g=temp.g+edge1[i].val;
            tt.f=tt.g+dis[tt.to];
            q.push(tt);
        }
    }
    return -1;
}
int main()
{
    int i,j,m;
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(i=0;i<m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add1(x,y,z);//原图
            add2(y,x,z);//反向图
        }
        int s,t,k;
        scanf("%d%d%d",&s,&t,&k);
        spfa(t);
        int ans=A_star(s,t,k);
        printf("%d\n",ans);
    }
}
时间: 2024-10-11 07:03:19

poj2449第K短路问题(A*算法)的相关文章

(WA)POJ2449 第K短路

POJ2449 第K短路 改了好长时间发现读入读反了qwq A*,先在反向图上求出每个点到t的最短距离,作为估价函数即可 疑问:能不能直接记录h+g 1 #include <cstdio> 2 #include <cstring> 3 #include <cctype> 4 #include <algorithm> 5 #include <queue> 6 #include <iostream> 7 using namespace s

poj2449 第k短路

题目链接 学习博客:https://blog.csdn.net/Z_Mendez/article/details/47057461 k短路没有我想象的那么难,还是很容易理解的 求s点到t点的第k短路径 先求出t到所有点的最短路径,用g[i]表示t到i的距离 从s开始"bfs",按照(g[i]+bfs路过的长度)构造优先队列,比如刚开始bfs路过长度为0,所在点为s 一直选择最小的(g[i]+bfs路过的长度),第一次到达t一定是从s沿着最短路径到达. 直到第k次到达t 理解代码可能更容

BZOJ1073 k短路(A*算法)

A*算法,也叫启发式搜索,就是设计一个预估函数,然后在搜索的过程中进行有序的搜索,我们设到目前状态的花费为f(x),到目标状态的估计花费为h(x),那么我们按照h(x)+f(x)排序即可,这道题里起点到目前的距离为f(x),目前到终点的最短路为g(x),然后进行暴力搜索即可.—— by VANE #include<bits/stdc++.h> using namespace std; const int N=55; const int M=10050; const int inf=1e9; i

POJ2449 (k短路)

#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <queue> using namespace std; #define maxn 2008 #define maxm 2000008 #define INF 2000000000 int lt[maxn],LT[maxn],sum=1,SUM=1; int h[maxn]; in

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

POJ2449:K短路

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

K短路【模板】

A*+SPFA算法: (1)将有向图的所有边正向.反向分别存入两个不同的边集(Edges,Edges1)中.用反向边集,以所求终点t为源点,利用SPFA或Dijkstra求解出所有点到t的最短路径,用Dist[i]数组来表示点i到点t的最短距离. (2)建立一个优先队列,将源点s加入到队列中. (3)从优先队列中取出最小的点p,如果点p == t,则计算t出队的次数.如果当前路径长度就是s到t的第k短路长度,算法结束.否则遍历与p相连的所有的边,将扩展出的到p的邻接点信息加入到优先队列中取. 注

BZOJ 1975 SDOI2010 魔法猪学院 A*k短路

题目大意:给定一个值E 求起点到终点的最多条路径 使长度之和不超过E k短路的A*算法--每一个点有一个估价函数=g[x]+h[x] 当中g[x]是从源点出发已经走了的长度 h[x]是从这个点到汇点的最短路 首先先在反图上跑一遍SPFA求出每一个点的h[x],然后将源点的g[x]+h[x]增加堆 每次取出堆顶时将堆顶的g[x]向所连接的边扩展 第k次取出汇点即是答案 当中有一个剪枝就是当第k+1次取出某个点时不继续拓展 防止MLE 可是这里k未知 我们能够对k进行估价处理 初始k=floor(E

【转】K短路

K短路 用dijsktra+A*启发式搜索 当点v第K次出堆的时候,这时候求得的路径是k短路.A*算法有一个启发式函数f(p)=g(p)+h(p), 即评估函数=当前值+当前位置到终点的最短距离g(p):当前从s到p点所走的路径长度,h(p)就是点p到目的点t的最短距离.f(p)就是当前路径从s走到p在从p到t的所走距离.步骤:1>求出h(p).将有向边反向,求出目的点t到所有点的最短距离,用dijkstra算法2>将原点s加入优先队列中3>优先队列取出f(p)最小的一个点p如果p==t