• 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)

    输出格式

    输出一行一个整数,为最少花费。


    建立 ((k+1)n) 个点,其中第 (i*n+j) 个表示的是已经使用了(i)次免费机会,目前在第 (j) 个实际节点的最短距离
    这是一个分层的感觉,以只能用一次免费机会为例,没用过的是一张图,用过的是一张图,这每张图内部的边就按照题目信息连接就行
    然后还有两张图之间的边,像这样,(u',v')指的是用过免费机会以后的那个图:

    (u ightarrow v',v ightarrow u')的权值为(0),意思是花费(0)的代价可以用一次免费机会来走这些边
    而在每张图内部的边权值是(len),意思时不花费免费机会需要用 (len) 的代价来走

    然后跑一边 dij 就行,但是当他的终点是(end),实际路程要为:(min_{i=0}^k dis(i*n+end))
    因为不一定每一次机会都要用

    在我们构建的这张分层的图中,点数是 ((k+1)n),边数是 (m(2k+1))

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<map>
    #include<iomanip>
    #include<cstring>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    int n,m,k;
    int start,end;
    int nex[2100006],to[2100006],w[2100006];
    int fir[110006],tot;
    int heap[110006],size;
    int dis[110006],in[110006];
    inline void add(int u,int v,int len){
    	to[++tot]=v;w[tot]=len;
    	nex[tot]=fir[u];fir[u]=tot;
    }
    inline void link(int u,int v,int len){
    	add(u,v,len);add(v,u,len);
    }
    inline void push(int x){
    	heap[++size]=x;
    	reg int i=size,fa;
    	while(i>1){
    		fa=i>>1;
    		if(dis[heap[fa]]<=dis[heap[i]]) return;
    		std::swap(heap[fa],heap[i]);i=fa;
    	}
    }
    inline int pop(){
    	int ret=heap[1];heap[1]=heap[size--];
    	int i=1,ls,rs;
    	while((i<<1)<=size){
    		ls=i<<1;rs=ls|1;
    		if(rs<=size&&dis[heap[rs]]<dis[heap[ls]]) ls=rs;
    		if(dis[heap[ls]]>=dis[heap[i]]) break;
    		std::swap(heap[i],heap[ls]);i=ls;
    	}
    	return ret;
    }
    inline int dij(){
    	std::memset(dis,0x3f,sizeof dis);dis[start]=0;
    	push(start);in[start]=1;
    	while(size){
    		reg int u=pop(),v;in[u]=0;
    		for(reg int i=fir[u];i;i=nex[i]){
    			v=to[i];
    			if(dis[v]>dis[u]+w[i]){
    				dis[v]=dis[u]+w[i];
    				if(!in[v]) push(v),in[v]=1;
    			}
    		}
    	}
    	int ans=2e9;
    	for(reg int i=0;i<=k;i++) ans=std::min(ans,dis[i*n+end]);
    	return ans;
    }
    int main(){
    	n=read(),m=read(),k=read();
    	start=read()+1;end=read()+1;
    	for(reg int u,v,len,i=1;i<=m;i++){
    		u=read()+1;v=read()+1;len=read();
    		link(u,v,len);
    		for(reg int j=1;j<=k;j++) link(j*n+u,j*n+v,len),add((j-1)*n+u,j*n+v,0),add((j-1)*n+v,j*n+u,0);
    	}
    	std::printf("%d",dij());
    	return 0;
    }
    
  • 相关阅读:
    使用python scrapy爬取知乎提问信息
    [java基础]一文理解java多线程必备的sychronized关键字,从此不再混淆!
    python scrapy 登录知乎过程
    python scrapy爬虫框架概念介绍(个人理解总结为一张图)
    【干货】一文理解Druid原理架构(时序数据库,不是ali的数据库连接池)
    2016年我所面试过的那些公司
    写在2017年1月
    分页pagination实现及其应用
    inconsistent line count calculation in projection snapshot
    来去匆匆
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12689916.html
Copyright © 2020-2023  润新知