• sss


    <更新提示>

    <第一次更新>


    <正文>

    飞行路线(luoguP4568)

    Description

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

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

    Input Format

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

    Output Format

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

    Sample Input

    5 6 1
    0 4
    0 1 5
    1 2 5
    2 3 5
    3 4 5
    2 3 3
    0 2 100
    

    Sample Output

    8
    

    解析

    这是一道分层图最短路模板题呢...
    那好吧,如果我们将(k)次免费搭乘机会无视的话,这就是裸的最短路。那么对于这种情况,我们可以考虑改进最短路算法。类似于(DP)的思想,我们将状态加维。
    对于(dis[i][j]),我们认为它代表到了节点(i),用了(j)次免费搭乘机会的最小花费。那么,在转移时我们就有两种选择:

    1. 使用免费搭乘机会
    2. 不使用免费搭乘机会

    在满足最短路三角形不等式和使用次数不超过(k)的前提下,我们对两种情况分别转移即可。
    对应的(vis)数组,我们也需要开成二维记录访问状态。

    事实上,这样的二维数组对应了(k)张图,这种模型我们称之为分层图最短路模型。对于这道题,堆优化(Dijkstra)即可解决。

    在输出答案时,由于不一定(k)次机会全部都要使用,我们需要在(f[end][i])中取最小值。

    (Code:)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=10000+20,M=50000+20,K=10+2;
    struct edge{int ver,val;};
    struct node
    {
    	int val,index,cnt;
    	bool operator <(const node temp)const
    	{
    		return this->val<temp.val;
    	}
    	bool operator >(const node temp)const
    	{
    		return this->val>temp.val;
    	}
    };
    int n,m,k,begin,end,vis[N][K],dis[N][K],ans=0x3f3f3f3f;
    vector< edge > Link[M];
    priority_queue< node,vector< node >,greater< node > > Heap;
    inline void input(void)
    {
    	scanf("%d%d%d",&n,&m,&k);
    	scanf("%d%d",&begin,&end);
    	begin++;end++;
    	for(int i=1;i<=m;i++)
    	{
    		int x,y,v;
    		scanf("%d%d%d",&x,&y,&v);
    		x++;y++;
    		Link[x].push_back(edge{y,v});
    		Link[y].push_back(edge{x,v});
    	}
    }
    inline void dijkstra()
    {
    	memset(dis,0x3f,sizeof dis);
    	dis[begin][0]=0;
    	Heap.push(node{0,begin,0});
    	while(!Heap.empty())
    	{
    		node temp=Heap.top();
    		Heap.pop();
    		if(vis[temp.index][temp.cnt])continue;
    		vis[temp.index][temp.cnt]=true;
    		for(int i=0;i<Link[temp.index].size();i++)
    		{
    			edge v=Link[temp.index][i];
    			if(temp.cnt<k&&dis[v.ver][temp.cnt+1]>dis[temp.index][temp.cnt])
    			{
    				dis[v.ver][temp.cnt+1]=dis[temp.index][temp.cnt];
    				Heap.push(node{dis[v.ver][temp.cnt+1],v.ver,temp.cnt+1});
    			}
    			if(dis[v.ver][temp.cnt]>dis[temp.index][temp.cnt]+v.val)
    			{
    				dis[v.ver][temp.cnt]=dis[temp.index][temp.cnt]+v.val;
    				Heap.push(node{dis[v.ver][temp.cnt],v.ver,temp.cnt});
    			}
    		}
    	}
    }
    int main(void)
    {
    	input();
    	dijkstra();
    	for(int i=0;i<=k;i++)ans=min(ans,dis[end][i]);
    	printf("%d
    ",ans);
    	return 0;
    }
    

    <后记>

  • 相关阅读:
    NO.6: 若不想编译器提供自动生成的函数,就应该明确拒绝
    NO.5: 了解C++编译器默认为你生成的构造/赋值/析构
    NO.4: 确定对象被使用前已被初始化
    NO.3: 尽量使用const
    NO.2: 尽量以const,enum,inline 替换 #define
    NO.1: 视C++为一个语言联邦
    C/C++ exception类
    C/C++ 类成员函数指针 类成员数据指针
    c++中的 Stl 算法(很乱别看)
    自定义类签发校验token-实现多方式登录-自定义反爬类-admin后台表管理字段自定义-群查接口-搜索-排序-分页
  • 原文地址:https://www.cnblogs.com/Parsnip/p/10362924.html
Copyright © 2020-2023  润新知