POJ 2449 Remmarguts' Date(k短路)

61 篇文章 0 订阅

Description
给出一张n个点m条边的无向图,问从s到t的路径中第k短的路径长度
Input
第一行两个整数n和m表示点数和边数,之后m行每行三个整数a,b,c表示a点和b点之间有一条权值为c的边,之后三个整数s,t,k表示求s到t的k短路
Output
输出从s到t的路径中第k短的路径长度
Sample Input
2 2
1 2 5
2 1 4
1 2 2
Sample Output
14
Solution
k短路,spfa+A*求解
设估价函数f(p)=g(p)+h(p),其中g(p)为当前从s到该点的路径长度,h(p)为该点到t的最短路(在原图的反图上以t为起点做一遍spfa可以得到),那么在bfs这张图时当终点出队列k次时g(t)即为第k短路长度
注意当s=t时需要计算k+1短路,因为s到t这条距离为0的路不算在k短路之中
Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 1111
#define maxm 111111
struct Edge
{
    int to,next,c;
}edge1[maxm],edge2[maxm];
int head1[maxm],tot1,head2[maxn],tot2;
int dis[maxn];
struct node
{
    int to,g,f;
    bool operator < (const node &a)const
    {
        if(a.f==f)return a.g<g;
        return a.f<f;
    }
};
void init() 
{
    tot1=tot2=0;
    memset(head1,-1,sizeof(head1));
    memset(head2,-1,sizeof(head2));
}
void add(int u,int v,int c)
{
    edge1[tot1].c=c;
    edge1[tot1].to=v;
    edge1[tot1].next=head1[u];
    head1[u]=tot1++;
    edge2[tot2].c=c;
    edge2[tot2].to=u;
    edge2[tot2].next=head2[v];
    head2[v]=tot2++;
}
void spfa(int s,int V)
{
    bool vis[maxn];
    memset(vis,false,sizeof(vis));
    queue<int>que;
    for(int i=0;i<=V;i++)dis[i]=INF;
    dis[s]=0;
    vis[s]=true;
    que.push(s);
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        vis[u]=false;
        for(int i=head2[u];i!=-1;i=edge2[i].next)
        {
            int v=edge2[i].to;
            int c=edge2[i].c;
            if(dis[v]>dis[u]+c)
            {
                dis[v]=dis[u]+c;
                if(!vis[v])
                {
                    vis[v]=true;
                    que.push(v);
                }
            }
        }
    }
}
int kth_length(int s,int t,int k)
{
    node e,temp;
    int cnt=0;
    priority_queue<node>que;
    if(s==t)k++;
    if(dis[s]==INF)return -1;
    e.to=s,e.g=0,e.f=dis[s];
    que.push(e);
    while(!que.empty())
    {
        e=que.top();
        que.pop();
        if(e.to==t)cnt++;
        if(cnt==k)return e.g;
        for(int i=head1[e.to];~i;i=edge1[i].next)
        {
            temp.to=edge1[i].to;
            temp.g=e.g+edge1[i].c;
            temp.f=temp.g+dis[temp.to];
            que.push(temp);
        }
    }
    return -1;
}
int main()
{
     int n,m,u,v,c,s,t,k;
     while(~scanf("%d%d",&n,&m))
     {
        init();
        while(m--)
        {
            scanf("%d%d%d",&u,&v,&c);
            add(u,v,c);
        }
        scanf("%d%d%d",&s,&t,&k);
        spfa(t,n);
        int ans=kth_length(s,t,k);
        printf("%d\n",ans);
     }
     return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值