首页 > 其他分享 >最短路+二分题目整理

最短路+二分题目整理

时间:2023-04-30 09:55:05浏览次数:52  
标签:二分 dist int double 短路 mid st return 题目

前往奥格瑞玛的道路

题目链接
\(\qquad\)题目要求最小化最大费用,显然是使用二分答案,二分答案首先应该看限制目标,此处的限制是血量限制,而目标是费用目标。这种情况我们可以二分费用,然后在图上跑最短路判定血量是否满足。
\(\qquad\)对于check函数,我们去判定是否存在一条道路使得最高费用不超过mid,并且小号血量不超过hp,我们对于所有目的点费用不超过mid的点跑最短路,判定是否满足hp的限制即可。

代码

#include <bits/stdc++.h>
#define pb emplace_back

using namespace std;
using PII = pair<int, int>;

const int N = 1e5 + 10;
vector<PII> h[N];
int n, m, hp, hh, tt;
int cost[N], dist[N], st[N], q[N];

bool check(int mid) {
	if (cost[1] > mid) return 0;
	memset(dist, 0x3f, sizeof dist);
	memset(st, 0, sizeof dist);
	hh = tt = 0;
	q[0] = 1, st[1] = 1, dist[1] = 0;

	while (hh <= tt) {
		int t = q[hh ++ ];
		st[t] = 0;
		for (auto k : h[t]) {
			int v = k.first, w = k.second;
			if (cost[v] > mid) continue ;
			if (dist[v] > dist[t] + w) {
				dist[v] = dist[t] + w;
				if (!st[v]) st[v] = 1, q[ ++ tt] = v;
			}
		}
	}

	return dist[n] <= hp;
}

int main() {
	scanf("%d%d%d", &n, &m, &hp);
	for (int i = 1; i <= n; i ++ ) scanf("%d", &cost[i]);
	while (m -- ) {
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		h[u].pb(v, w), h[v].pb(u, w);
	}

	int l = 0, r = 1e9 + 1;
	while (l < r) {
		int mid = l + r >> 1;
		if (check(mid)) r = mid;
		else l = mid + 1;
	}
	if (r == 1e9 + 1) puts("AFK");
	else printf("%d\n", r);

	return 0;
}

Telephone Lines S

题目链接
\(\qquad\)我们可以取消 \(\le K\) 条道路的价值,并取得剩下的道路中最贵的。很容易想到一个贪心的策略,那就是取消最贵的 \(K\) 条路的价值,这样我们剩下的就是第 \(K + 1\) 贵的边了。
题目让我们最小化这个值,也就是让我们最小化 K + 1 大值,也可以采用二分。当然如果比它大的值小于 \(K\) 的时候,直接全部删除即可。
\(\qquad\)二分之前我们同样先看下限制目标,这题的限制应该是更大值限制,而目标是最小费用目标,所以我们可以二分一下费用,并且判定是否在 \(1\sim N\)的路上有不超过 \(K\) 条边比它大即可。

代码

#include <bits/stdc++.h>
#define pb emplace_back

using namespace std;
using PII = pair<int, int>;

const int N = 1010;
vector<PII> h[N];
int n, m, k, st[N], dist[N];

bool check(int mid) {
	memset(dist, 0x3f, sizeof dist);
	memset(st, 0, sizeof st);
	queue<int> q;

	q.push(1), st[1] = 1, dist[1] = 0;
	while (q.size()) {
		int t = q.front();
		q.pop(), st[t] = 0;
		for (auto k : h[t]) {
			int v = k.first, w = k.second;
			int W = w > mid;
			if (dist[v] > dist[t] + W) {
				dist[v] = dist[t] + W;
				if (!st[v]) st[v] = 1, q.push(v);
			}
		}
	}

	return dist[n] <= k;
}

int main() {
	scanf("%d%d%d", &n, &m, &k);
	while (m -- ) {
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		h[u].pb(v, w), h[v].pb(u, w);
	}

	int l = 0, r = 1e6 + 1;
	while (l < r) {
		int mid = l + r >> 1;
		if (check(mid)) r = mid;
		else l = mid + 1;
	}
	printf("%d\n", r == 1e6 + 1 ? -1 : r);

	return 0;
}

Sightseeing Cows G

题目链接
\(\qquad\)这题是平均值最小问题,可以二分平均值,没有特殊的限定条件。
\(\large mid\le \frac{\sum w}{\sum t}\Rightarrow mid\times \sum t \le \sum w\Rightarrow mid\times \sum t - \sum w <= 0\)
所以我们是在原图上判负环和零环即可。

#include <bits/stdc++.h>
#define pb emplace_back

using namespace std;
using PII = pair<int, int>;

const int N = 1010;
vector<PII> h[N];
int n, m, st[N], f[N];
double dist[N];

bool dfs(int u, double mid) {
	st[u] = 1;
	for (auto k : h[u]) {
		int v = k.first, w = k.second;
		double W = w * mid - f[v];
		if (dist[v] >= dist[u] + W) {
			dist[v] = dist[u] + W;
			if (st[v]) { st[v] = 0; return 1; }
			if (dfs(v, mid)) { st[v] = 0; return 1; }
		}
	}
	return st[u] = 0;
}

bool check(double mid) {
	int ring = 0;
	memset(st, 0, sizeof st);
	for (int i = 1; i <= n; i ++ ) {
		if (ring) break ;
		if (st[i]) continue ;
		ring |= dfs(i, mid);
	}
	return ring;
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i ++ ) scanf("%d", &f[i]);
	while (m -- ) {
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		h[u].pb(v, w);
	}

	double l = 0, r = 1001;
	while (r - l > 1e-4) {
		double mid = (l + r) / 2;
		if (check(mid)) l = mid;
		else r = mid;
	}
	printf("%.2lf\n", r);

	return 0;
}

Word Rings

题目链接
\(mid\le \frac{\sum w}{cnt}\Rightarrow mid\times cnt\le \sum w\Rightarrow \sum (mid-w)\le 0\)
判一下零环和负环即可。
注意的是这里的建图方式。我们要求图上包含的信息是:点一定是给定字符串的头两个或尾两个字符;字符串的长度。我们由此可以想到只对于每个字符串连接首尾两个的字符,边权为字符串长度,然后与上题相同。

#include <bits/stdc++.h>
#define pb emplace_back

using namespace std;
using PII = pair<int, int>;

const int N = 1010;
vector<PII> h[N];
int n, m, st[N];
double dist[N];

bool dfs(int u, double mid) {
	st[u] = 1;
	for (auto k : h[u]) {
		int v = k.first, w = k.second;
		double W =  mid - w;
		if (dist[v] > dist[u] + W) {
			dist[v] = dist[u] + W;
			if (st[v]) { st[v] = 0; return 1; }
			if (dfs(v, mid)) { st[v] = 0; return 1; }
		}
	}
	return st[u] = 0;
}

bool check(double mid) {
	int ring = 0;
	memset(st, 0, sizeof st);
	for (int i = 1; i <= 676; i ++ ) {
		if (ring) break ;
		if (st[i]) continue ;
		ring |= dfs(i, mid);
	}
	return ring;
}

int main() {
	while (scanf("%d", &n), n) {
		for (int i = 1; i <= 676; i ++ ) h[i].clear();
		string s;
		for (int i = 1; i <= n; i ++ ) {
			cin >> s;
			int a, b, sz = s.size();
			a = (s[0] - 'a') * 26 + s[1] - 'a' + 1;
			b = (s[sz - 2] - 'a') * 26 + s[sz - 1] - 'a' + 1;
			h[a].pb(b, sz);
		}
		if (!check(0)) puts("No solution");
		else {
			double l = 0, r = 100001;
			while (l < r - 1e-5) {
				double mid = (l + r) / 2;
				if (check(mid)) l = mid;
				else r = mid;
			}
			printf("%.2lf\n", r);
		}
	}

	return 0;
}

标签:二分,dist,int,double,短路,mid,st,return,题目
From: https://www.cnblogs.com/StkOvflow/p/17364629.html

相关文章

  • OOP4-6题目集总结
    4-6次题目集,从集合框架,正则表达式,类的继承与多态三个方面展开,在帮助我们了解java常用的工具(集合框架,正则表达式)的同时让我们学着利用类与类之间的关系来减少耦合,第六次题目集侧重于类的继承与多态,同时让我们自己根据题目设计类来解题,在了解面向对象的编程思想后,加强我们对类与......
  • Java学习2——第四-六次题目集的分析与总结
     一.前言 本次Blog是对java学习中第二阶段练习的一个总结,作为刚学习JAVA的小白,以下依旧只是本人作为普通学生,以当前能力和状态所做出的总结和分析,不足之处也欢迎各位大佬的指正! 这次的三个题目集,题量除了题目集六很少外,其它都是正常数量,当然题目集六的题也是最难的。总体难......
  • 题目集4-6总结
    一、前言本阶段的题目集最开始还是和前面的题目集有些相似的内容,但相较于前阶段的题目集主要是改进了代码所用到的知识点使代码更加简洁与所用内存更加小。这次题目集的难度还可以,并且是逐渐加大难度的,特别是题目集六一道题一百分。这次的题目集主要考察了正则表达式的应用,类与类......
  • OOP 4-6题目集总结
    目录前言设计与分析踩坑心得改进建议总结一、前言      (1)第四次题目集           本次题目集一共有7道题目,题量适中,但第一题难度较大,其余题目难度适中。考察的知识点有类与类之间的关系调用、对象数组的使用、排序、String类方法的使......
  • 4-6次题目集总结
    前言:4-6次pta实验相较于之前三次难度有所提升,主要是为了训练我们对于java类的设计以及类内方法的设计,以及很多语法知识,是正式进入java的过程。题目集四:主要知识点是一些语法的使用,类的设计,以及类的方法体,需要考虑输出格式和算法设计,如正则表达式,LinkedHashSet去重等,题目难度不低......
  • PTA题目集4~6的总结
    1.前言题目集4题目集4题目量适中,整体难度中偏易题目7-1要求厘清类与类间的关系,能对题目所给的要求作出准确的设计,难度中偏上题目7-2~7-7考察基本的算法,对Java中集合框架的使用以及对LocalDate类的使用,总体上难度偏易题目集5......
  • Java题目集4~6的总结
    1.前言第四次作业主要涉及的知识点有通过查询JavaAPI文档,了解Scanner类中nextLine()等方法、String类中split()等方法、Integer类中parseInt()等方法的用法,了解LocalDate类中of()、isAfter()、isBefore()、until()等方法的使用规则,了解ChronoUnit类中DAYS、WEEKS、MONTHS等单位......
  • 数的范围 | 整数二分
    AC.789数的范围题目描述给定一个按照升序排列的长度为\(n\)的整数数组,以及\(q\)个查询。对于每个查询,返回一个元素\(k\)的起始位置和终止位置(位置从\(0\)开始计数)。输入格式第一行包含整数\(n\)和\(q\),表示数组长度和询问个数。第二行包含n个整数(均在\(1∼1000......
  • 题目集4-6
     第二次blog作业1.前言作为一个java和面向对象的初学者,在写题目这方面确实是处处碰壁,但学习最重要的是坚持,希望我能够坚持下去。对于这三次的题目集,就难度而言是比较难的,难在一些测试点需要经过深层次的思考,还要通过大量的测试测试出来,必须承认的是考到的一些知识在题目中都有......
  • 「学习笔记」重修最短路
    \(u\)到\(v\)的最短路径的长度就是\(u\)到\(v\)的最短路。单源最短路算法可以求出一个点到其他点的最短路。全源最短路算法可以求出每一个点到其他各点的最短路。松弛操作:dis[v]=min(dis[v],dis[u]+w);。算法Floyd算法全源最短路算法,时间复杂度\(O_{n^3}\),......