zoukankan      html  css  js  c++  java
  • 洛谷 P4568 [JLOI2011]飞行路线

    洛谷 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。

    输出格式

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

    输入输出样例

    输入 #1

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

    输出 #1

    8
    

    说明/提示

    对于30%的数据,(2 le n le 50,1 le m le 300,k=0;)
    对于50%的数据,(2 le n le 600,1 le m le 6000,0 le k le 1;)
    对于100%的数据,(2 le n le 10000,1 le m le 50000,0 le k le 10,0 le s,t<n,0 le a,b<n,a eq b,0 le c le 1000)

    题解:

    分层图最短路

    思路就是建一个(K)层的图(平面内开k倍),之后按照加边规则把每条边在k层平面内都加好,之后同样的两个点在相邻层中建一条边权为(0)的边,这样构成了所给的(K)条免费的路径。

    分层图加边代码(链式前向星):

    for (int i = 1; i <= m; i ++ )
    {
    	int x, y, z;
    	scanf("%d%d%d", &x, &y, &z);
    	add(x ,y, z);
    	add(y, x, z);
    	for (int j = 1; j <= k; j ++ )
    	{
    		add(x + (j - 1) * n, y + j * n, 0);
    		add(y + (j - 1) * n, x + j * n, 0);
    		add(x + j * n, y + j * n, z);
    		add(y + j * n, x + j * n, z);
    	}
    }
    

    不过这道题有大坑!!!

    首先的确给了我们K个免费机会,但是我们不确定最优解是否一定用光了这K次机会(例如说最优解边数<K),那么我们需要加一个循环搜索最小值的过程。

    其次是在这道题中的数据,数组要开……估算40倍!!!首先因为是分层图,并且每一条边都是双相边,这里数组一定要够大!!!!!(本蒟蒻在这里被疯狂卡)

    AC代码

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 4e5 + 10;
    
    const int M = 3e6 + 10;
    
    int n, m, k, s, t, vis[N], dis[N];
    
    int tot, to[M], val[M], nex[M], head[N];
    
    void add(int x, int y, int z)
    {
    	to[ ++ tot] = y;
    	val[tot] = z;
    	nex[tot] = head[x];
    	head[x] = tot;
    }
    
    priority_queue < pair<int, int> > q;
    
    void dijkstra(int s)
    {
    	memset(vis, 0, sizeof vis);
    	memset(dis, 0x3f, sizeof dis);
    
    	dis[s] = 0;
    	q.push(make_pair(0, s));
    	while (!q.empty())
    	{
    		int x = q.top().second;
    		q.pop();
    		if (vis[x])
    			continue ;
    		vis[x] = 1;
    		for (int i = head[x]; i; i = nex[i])
    		{
    			if (dis[to[i]] > dis[x] + val[i])
    			{
    				dis[to[i]] = dis[x] + val[i];
    				q.push(make_pair(-dis[to[i]], to[i]));
    			}
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%d%d", &n, &m, &k);
    	scanf("%d%d", &s, &t);
    	for (int i = 1; i <= m; i ++ )
    	{
    		int x, y, z;
    		scanf("%d%d%d", &x, &y, &z);
    		add(x ,y, z);
    		add(y, x, z);
    		for (int j = 1; j <= k; j ++ )
    		{
    			add(x + (j - 1) * n, y + j * n, 0);
    			add(y + (j - 1) * n, x + j * n, 0);
    			add(x + j * n, y + j * n, z);
    			add(y + j * n, x + j * n, z);
    		}
    	}
    	dijkstra(s);
    	int ans = 0x3f3f3f3f;
    	for (int i = 0; i <= k; i ++ )
    	{
    		ans = min(ans, dis[t + i * n]);
    	}
    
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    idea添加类注释和方法注释
    蓝桥杯ALGO-1,区间k大数查询
    personalblog
    ul+li水平居中的几种方法
    前端ps部分
    帝国cms-tab
    帝国cms判断某一字段是否为空
    帝国cms建站总结-(分页)
    Js获取验证码倒计时
    前端截取字符串:JS截取字符串之substring、substr和slice详解
  • 原文地址:https://www.cnblogs.com/littleseven777/p/11849186.html
Copyright © 2011-2022 走看看