HYSBZ

题目:

Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并且航线有一定的价格。Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多k种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少?

思路:

典型的分层图求最短路问题,这类问题一般适用于我们要对图中的某些边的权进行变换的情况,当然变换的次数要很小才行。

d[u][j]表示到达u点已经免费乘坐了j次航线的最短距离。在套一个裸的迪杰斯特拉算法就可以了。

代码:

//#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#define MAX 1000000000
#define inf 0x3f3f3f3f
#define FRE() freopen("in.txt","r",stdin)

using namespace std;
typedef long long ll;
const int maxn = 10005;
int n,m,k,s,t;
int d[maxn][15];
struct Edge
{
    int to,c;
};
vector<Edge> mp[maxn];
struct Node
{
    int u,k,d;
    bool operator<(const Node& rhs)const{
        return d>rhs.d;
    }
};

void Dij()
{
    for(int i=0; i<=k; i++) d[s][i] = 0;
    priority_queue<Node> que;
    que.push(Node{s,0,0});
    while(!que.empty())
    {
        Node u = que.top();
        que.pop();
        if(u.d>d[u.u][u.k]) continue;
        for(int i=0; i<mp[u.u].size(); i++)
        {
            Edge e = mp[u.u][i];//可以将这里的分层图看做是dp来理解
            if(u.d+e.c<d[e.to][u.k])//不乘坐免费的情况
            {
                d[e.to][u.k] = u.d+e.c;
                que.push(Node{e.to,u.k,u.d+e.c});
            }
            if(u.k+1<=k && d[e.to][u.k+1]>d[u.u][u.k])//免费乘坐的情况
            {
                d[e.to][u.k+1] = d[u.u][u.k];
                que.push(Node{e.to,u.k+1,d[u.u][u.k]});
            }
        }
    }
    return ;
}


int main()
{
    //FRE();
    memset(d,inf,sizeof(d));
    scanf("%d%d%d",&n,&m,&k);
    scanf("%d%d",&s,&t);
    for(int i=0; i<m; i++)
    {
        int u,v,c;
        scanf("%d%d%d",&u,&v,&c);
        mp[u].push_back(Edge{v,c});
        mp[v].push_back(Edge{u,c});
    }
    Dij();
    int ans = inf;
    for(int i=0; i<=k; i++)
    {
        ans = min(ans,d[t][i]);
    }
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/sykline/p/10498852.html