首页 > 其他分享 >【LuoGU 1462】通往奥格瑞玛的道路——最短路+二分

【LuoGU 1462】通往奥格瑞玛的道路——最短路+二分

时间:2023-08-05 17:01:49浏览次数:31  
标签:瑞玛 奥格 int LuoGU 城市 long leq 1462

通往奥格瑞玛的道路

题目背景

在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量。

有一天他醒来后发现自己居然到了联盟的主城暴风城。

在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛。

题目描述

在艾泽拉斯,有 \(n\) 个城市。编号为 \(1,2,3,\ldots,n\)。

城市之间有 \(m\) 条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。

每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。

假设 \(1\) 为暴风城,\(n\) 为奥格瑞玛,而他的血量最多为 \(b\),出发时他的血量是满的。如果他的血量降低至负数,则他就无法到达奥格瑞玛。

歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。

输入格式

第一行 \(3\) 个正整数,\(n,m,b\)。分别表示有 \(n\) 个城市,\(m\) 条公路,歪嘴哦的血量为 \(b\)。

接下来有 \(n\) 行,每行 \(1\) 个正整数,\(f_i\)。表示经过城市 \(i\),需要交费 \(f_i\) 元。

再接下来有 \(m\) 行,每行 \(3\) 个正整数,\(a_i,b_i,c_i\)(\(1\leq a_i,b_i\leq n\))。表示城市 \(a_i\) 和城市 \(b_i\) 之间有一条公路,如果从城市 \(a_i\) 到城市 \(b_i\),或者从城市 \(b_i\) 到城市 \(a_i\),会损失 \(c_i\) 的血量。

输出格式

仅一个整数,表示歪嘴哦交费最多的一次的最小值。

如果他无法到达奥格瑞玛,输出 AFK

样例 #1

样例输入 #1

4 4 8
8
5
6
10
2 1 2
2 4 1
1 3 4
3 4 3

样例输出 #1

10

提示

对于 \(60\%\) 的数据,满足 \(n\leq 200\),\(m\leq 10^4\),\(b\leq 200\);

对于 \(100\%\) 的数据,满足 \(1\leq n\leq 10^4\),\(1\leq m\leq 5\times 10^4\),\(1\leq b\leq 10^9\);

对于 \(100\%\) 的数据,满足 \(1\leq c_i\leq 10^9\),\(1\leq f_i\leq 10^9\),可能有两条边连接着相同的城市。

解法

二分 + Dijkstra最短路

个人感觉本题的一个难点在于读题:题目问的是经过的所有城市中//最多的一次收取的费用//的最小值。也就是要我们求在歪嘴哦经过的所有路径中,收过路费收的最多的这个城市收的过路费的最小值。也就是将一个城市收取的过路费的最大值最小化
察觉到关键词,于是就要往二分上靠。不难发现答案具有二段性:每个城市收的过路费的最大值越小,能走的路径就越少,能到达终点的可能性也越小。
然后题目中还有一个血量限制,这里就可以用到最短路了: 将血量消耗看成是边权,每二分出一个\(x\)后跑一遍Dijkstra,如果最短路的消耗都大于\(b\)则返回\(false\),否则返回\(true\)。
注意细节:
\(1、\)判断不可达:所有路径都能走的情况下最短路径的消耗依然大于\(b\),则歪嘴哦无法到达奥格瑞玛。
\(2、\)如果起点的过路费已经大于二分枚举出来的\(x\),则直接判断为假。该种情况需要特判!

#include<bits/stdc++.h>

typedef long long ll;

typedef std::pair<ll, ll> pll;

const int N = 100010;

int n, m, b;
std::vector<std::vector<pll>> g(N);
int f[N];
int maxf;
int blood;
bool flag;

bool dijkstra(int x) {
	std::vector<long long> dist(n + 1, LLONG_MAX);
	dist[1] = 0;

	std::priority_queue<pll, std::vector<pll>, std::greater<pll>> pq;
	pq.push({0, 1});

	while(!pq.empty()) {
		auto hh = pq.top();
		pq.pop();

		long long d = hh.first;
		int u = hh.second;
		if(d > dist[u]) continue;

		for(auto tt: g[u]){
			int v = tt.first, c = tt.second;
			if(f[v] > x) continue;
			long long new_d = d + (long long)c;
			if(new_d < dist[v]) {
				dist[v] = new_d;
				pq.push({dist[v], v});
			}
		}
	}
	return dist[n] <= b;
}

bool check(int x) {
	return dijkstra(x);
}

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);

	std::cin >> n >> m >> b;
	for(int i = 1; i <= n; i ++ ){
		std::cin >> f[i];
		maxf = std::max(f[i], maxf);
	}

	for(int i = 0; i < m; i ++ ){
		int a, b, c;
		std::cin >> a >> b >> c;
		g[a].push_back({b, c});
		g[b].push_back({a, c});
	}

	int l = 1, r = maxf;
	if(!check(r)) {
		std::cout << "AFK" << '\n';
		return 0;
	}
	while(l < r) {
		int mid = l + r >> 1;
		if(f[1] <= mid && check(mid)) r = mid;
		else l = mid + 1;
	}
	std::cout << r << '\n';
	return 0;
}

标签:瑞玛,奥格,int,LuoGU,城市,long,leq,1462
From: https://www.cnblogs.com/yjx-7355608/p/17608204.html

相关文章

  • [刷题笔记] LuoguP1156 垃圾陷阱
    ProblemDescription题目描述了几个状态,我们来理顺一下:一头牛掉进了坑里,农夫会在几个时段向下扔垃圾,牛初始可以撑10h,对于每一个垃圾,牛可以:把它堆起来,一旦垃圾堆的高度超过\(h\),她就可以爬出来吃掉它垃圾好吃吗,并且获得能量值需要注意的是,牛可以撑到下一次垃圾投放的标......
  • [刷题笔记] Luogu P2014 [CTSC1997] 选课
    ProblemSolution我们发现本题中有好多主从关系,即要想取用一个儿子必须先取用她的父亲。构成了一个森林,处理不便。有个小技巧,就是将0号节点参与建树,最后所求节点数就变成了\(m+1\),且把森林变成了一棵树。然后如何处理呢?再次理解题意,我们发现,我们每次的决策是是否取用儿子,取用......
  • [刷题笔记][算法模型总结] Luogu P1880 [NOI1995] 石子合并 || 区间dp之合并石子模型
    ProblemSolution本题还有一个弱化版,见LuoguP1775我们发现本题和弱化版唯一区别就是本题有环。我们先将弱化版的内容。EasyversionDescription弱化版是给定了好多堆石子,每相邻的两堆可以合并成一个大堆,每次合并会产生两个石头重量和的价值,最后会将若干堆石子合并为一堆。......
  • [Luogu P8744] 左孩子右兄弟 题解
    题目大意给定一棵节点个数为\(N\)的多叉树,求其通过"左孩子右兄弟"表示法转化成的二叉树,高度最高是多少。解决思路首先分辨出此题目是树状DP,并了解"左孩子右兄弟"表示法的转换方式,便开始考虑DP的状态转移方程。状态由于每个节点由\(1\)至\(N\)编号,那么就使用\(dp_{k......
  • 【题解】Luogu[P5022] [NOIP2018 提高组] 旅行
    Link因为是道NOIP,那么我们不妨按照考场上的策略一点一点想。先看部分分,有一档有很明显的特征\(n=m-1\)这显然构成一棵树,对于一棵树,我们想把他按照题目的要求遍历完,一定是像dfs的遍历顺序一样,对于一个点,必然遍历完以它为根的子树,才能回到它的父亲节点,于是就有了一个很明显的贪......
  • [刷题笔记] Luogu P1853 投资的最大效益
    ProblemSolution刚开始看这道题的时候不自主的想到了纪念品,但其实本题和纪念品还是有区别的。纪念品规定了每次只能买一个纪念品,而本题可以买无限个纪念品需要在原本的基础上买进卖出,钱有进有出,而本题时只有进,稳赚不赔。本题和纪念品不同的第一点决定了它时完全背包,纪念品......
  • [刷题笔记] Luogu P5662 [CSP-J2019] 纪念品
    ProblemDescription类似于炒股票,有买进有卖出,当天可以既买进又卖出无限次,现在有若干件物品,每件物品都有一个价格,每天每件物品的价格不一致,你初始有\(m\)元钱,想要通过若干次购进卖出的操作,使得\(T\)天后你手里的钱最多。要求:\(T\)天结束你手中的股票必须全部售出。Solution乍看......
  • [刷题笔记] Luogu P1466 [USACO2.2] 集合 Subset Sums
    ProblemDescription有一个长度为\(n\)的数组为\(1-n\),求有多少种选择方案使得选择数之和等于序列和的一半Solution题面翻译成这样是不是就好做了?首先,序列和的一半我们可以计算出\(n\times(n+1)\div2\div2\),显然序列和的一半只有是整数才有解,如果不是整数直接输出0即可。......
  • 【题解】Luogu[P2296] [NOIP2014 提高组] 寻找道路
    Link很简单的一道图论题。要在一个有向图上找一条\(s\)到\(t\)的最短路,要求这条路径上的所有点都满足:该点的所有出边所连点都能到达终点\(t\)。看上去很乱,我们简单分解一下,先在所有点中找到与终点有路径的点集\(A\)进行标记,再再所有点中找到其所有出边所连点都被打上标......
  • [刷题笔记] Luogu P2340 [USACO03FALL] Cow Exhibition G
    ProblemSolution乍看可能没有思路。我们注意到本题是牵扯到一头奶牛选or不选的问题,非常自然地想到01背包。接下来我们就尝试将本题背景转换成01背包问题。我们可以将智商转换成容量,情商转换成价值。(当然反过来也可)然后就可以套用01背包板子了:\[f_{i,j}=min(f_{i-1,j},f_{i-1......