POJ2449

Problem: Remmarguts’ Date
Description: 给你一个图,让你寻找第K短的路径从src点到des点。
Solution: A* +邻接表的迪杰斯特拉。这题目是ACM/ICPC上的一道例题。我用来加深了对A* 算法的理解和对邻接表的迪杰斯特拉的学习。我们先用迪杰斯特拉算法求出每一个点到des的距离用来当做评估条件,然后用A* 算法从src向下广搜。由于A* 算法有这朝最短路方向搜索的趋势,那么当第K次到达des时,这个时候的距离就是第K短路。代码是我自己理解后自己敲的。
Code(C++):

#include <stdio.h>
#include <string.h>

#include <queue>

#define INF 0x3f3f3f3f

using namespace std;

const int M=100005;

bool used[M];

int dis[M];
int head_a[M],head_b[M];

typedef struct tagEdge{
    int from,to;
    int value;
    int next;

    tagEdge(){}
    tagEdge(int _from,int _to,int _value,int _next):
        from(_from),to(_to),value(_value),next(_next){}
}Edge;

typedef struct tagNode{
    int to;
    int value;

    tagNode(){}
    tagNode(int _to,int _value):
        to(_to),value(_value){}
    bool operator<(const tagNode &other)const{
        return value+dis[to]>other.value+dis[other.to];
    }
}Node;

Edge edges_a[M],edges_b[M];

int n,m;
int edges_num;

int src,des,k;

void init()
{
    edges_num=0;
    memset(head_a,-1,sizeof(head_a));
    memset(head_b,-1,sizeof(head_b));
}

void add_edge(Edge *p,int *hd,int x,int y,int c)
{
    p[edges_num]=Edge(x,y,c,hd[x]);
    hd[x]=edges_num;
}

void dij(int des,Edge* edge,int *head)
{
    memset(used,false,sizeof(used));
    for(int i=1;i<=n;i++)
        dis[i]=INF;
    dis[des]=0;

    priority_queue<Node> que;
    que.push(Node(des,0));
    for(int i=1;i<n;i++){
        while(!que.empty()&&used[que.top().to])
            que.pop();
        if(que.empty())
            break;

        Node now=que.top();
        que.pop();
        used[now.to]=true;

        for(int j=head[now.to];j+1;j=edge[j].next)
            if(!used[edge[j].to]&&dis[edge[j].to]>dis[now.to]+edge[j].value){
                dis[edge[j].to]=dis[now.to]+edge[j].value;
                que.push(Node(edge[j].to,0));
            }
    }
}

int a_star(int src,Edge *edge,int *head)
{
    priority_queue<Node> que;
    que.push(Node(src,0));

    while(!que.empty()){
        Node now=que.top();
        que.pop();
        if(now.to==des){
            if(!k)
                return now.value;
            --k;
        }

        for(int i=head[now.to];i+1;i=edge[i].next)
            que.push(Node(edge[i].to,now.value+edge[i].value));
    }
    return -1;
}

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

        int x,y,c;
        while(m--){
            scanf("%d%d%d",&x,&y,&c);
            add_edge(edges_a,head_a,x,y,c);
            add_edge(edges_b,head_b,y,x,c);
            ++edges_num;
        }

        scanf("%d%d%d",&src,&des,&k);
        dij(des,edges_b,head_b);
        if(dis[src]>=INF){
            puts("-1");
            continue;
        }
        if(src==des)
            ++k;
        --k;
        int ans=a_star(src,edges_a,head_a);
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值