洛谷 P4568 [JLOI2011]飞行路线 解题报告

P4568 [JLOI2011]飞行路线

题目描述

Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在\(n\)个城市设有业务,设这些城市分别标记为0到\(n−1\) ,一共有\(m\)种航线,每种航线连接两个城市,并且航线有一定的价格。

Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多\(k\)种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少?

输入输出格式

输入格式:

数据的第一行有三个整数,\(n,m,k\),分别表示城市数,航线数和免费乘坐次数。
第二行有两个整数,\(s,t\),分别表示他们出行的起点城市编号和终点城市编号。
接下来有\(m\)行,每行三个整数, \(a,b,c\),表示存在一种航线,能从城市\(a\)到达城市\(b\),或从城市\(b\)到达城市\(a\),价格为\(c\)

输出格式:

只有一行,包含一个整数,为最少花费。


这是一个分层图+最短路的题目

一种做法是按深度建图+向更深的图连0边,但这里讨论类似于DP的一种思想。

\(dis[i][j]\)代表节点\(i\)在深度为\(j\)的时候的最短路。

按找dijk的思想进行三角形不等式松弛即可

据说这个题卡SPFA

实现看代码吧,我感觉挺好理解的。


#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int N=10010;
const int M=50010;
int head[N],cnt=0,to[M<<1],next[M<<1],edge[M<<1];
void add(int u,int v,int w)
{
    to[++cnt]=v;next[cnt]=head[u];edge[cnt]=w;head[u]=cnt;
}
struct node
{
    int i,dep,w;
    bool friend operator <(node n1,node n2)
    {
        return n1.w>n2.w;
    }
    node(){}
    node(int i,int dep,int w)
    {
        this->i=i;
        this->dep=dep;
        this->w=w;
    }
};
priority_queue <node> q;
int dis[N][12],used[N][12],n,m,k,s,t;
void dijk()
{
    memset(dis,0x3f,sizeof(dis));
    dis[s][0]=0;
    node tt(s,0,dis[s][0]);
    q.push(tt);
    while(!q.empty())
    {
        node from=q.top();
        q.pop();
        int dep=from.dep,u=from.i;
        if(used[u][dep]) continue;
        used[u][dep]=1;
        for(int i=head[u];i;i=next[i])
        {
            int v=to[i],w=edge[i];
            if(!used[v][dep]&&dis[v][dep]>dis[u][dep]+w)
            {
                dis[v][dep]=dis[u][dep]+w;
                node tt(v,dep,dis[v][dep]);
                q.push(tt);
            }
            if(dep<k&&!used[v][dep+1]&&dis[v][dep+1]>dis[u][dep])
            {
                dis[v][dep+1]=dis[u][dep];
                node tt(v,dep+1,dis[v][dep+1]);
                q.push(tt);
            }
        }
    }
}
int main()
{
    scanf("%d%d%d%d%d",&n,&m,&k,&s,&t);
    int u,v,w;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w),add(v,u,w);
    }
    dijk();
    printf("%d\n",dis[t][k]);
    return 0;
}


2018.6.20

posted @ 2018-06-20 18:39  露迭月  阅读(144)  评论(0编辑  收藏  举报