【图论经典题目讲解】CF715B - Complete The Graph

news/2024/7/15 18:08:03 标签: 图论, c++, 算法

C F 715 B − C o m p l e t e   T h e   G r a p h \mathrm{CF715B - Complete\ The\ Graph} CF715BComplete The Graph

D e s c r i p t i o n \mathrm{Description} Description

给定一张 n n n 个点, m m m 条边的无向图,点的编号为 0 ∼ n − 1 0\sim n-1 0n1,对于每条边权为 0 0 0 的边赋一个不超过 1 0 18 10^{18} 1018正整数权值,使得 S S S T T T 的最短路长度为 L L L

S o l u t i o n \mathrm{Solution} Solution

W a y   1 \mathrm{Way\ 1} Way 1

考虑将每 1 1 1 条长度为 0 0 0 的边记录出来,初始将其全部设置为 1 1 1(因为要求边权值 ∈ [ 1 , 1 0 18 ] \in[1,10^{18}] [1,1018]),如果将这些边依次不断地加 1 1 1,则 S S S T T T 的最短路的长度会不断地增加不变,总之最短路长度是单调不降的。那么,如果有解就必定会找到一种方案,反之则不会。

观察数据范围可知,最多每条边会加到 L L L,有 m m m 条边,那么时间应为 O ( m 2 L log ⁡ n ) O(m^2L\log n) O(m2Llogn),因为还需加入 Dijkstra 的时间复杂度。

显然,会 TLE。不过,上文已分析最短路的长度是单调不降的,所以满足二分的性质,可以二分总共加 1 1 1 的个数,然后对于每跳边先加 ⌊ 个数 边数 ⌋ \lfloor\frac{个数}{边数}\rfloor 边数个数,之后对于 1 ∼ 个数   m o d   边数 1\sim 个数\bmod 边数 1个数mod边数 的边再加 1 1 1 即可。

时间复杂度: O ( m log ⁡ L log ⁡ n ) O(m\log L\log n) O(mlogLlogn)

C o d e Code Code

#include <bits/stdc++.h>
#define int long long

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

const int SIZE = 2e4 + 10;

int N, M, L, S, T;
int h[SIZE], e[SIZE], ne[SIZE], w[SIZE], idx;
std::vector<int> Id;
int Dist[SIZE], Vis[SIZE];

void add(int a, int b, int c)
{
	e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
}

int Dijkstra()
{
	priority_queue<PII, vector<PII>, greater<PII>> Heap;
	memset(Dist, 0x3f, sizeof Dist);
	memset(Vis, 0, sizeof Vis);
	Dist[S] = 0, Heap.push({0, S});

	while (Heap.size())
	{
		auto Tmp = Heap.top();
		Heap.pop();

		int u = Tmp.second;
		if (Vis[u]) continue;
		Vis[u] = 1;

		for (int i = h[u]; ~i; i = ne[i])
		{
			int j = e[i];
			if (Dist[j] > Dist[u] + w[i])
			{
				Dist[j] = Dist[u] + w[i];
				Heap.push({Dist[j], j});
			}
		}
	}

	return Dist[T];
}

int Check(int X)
{
	for (auto c : Id)
		w[c] = X / (int)(Id.size() / 2);
	for (int i = 0; i < (X % (int)(Id.size() / 2)) * 2; i += 2)
		w[Id[i]] += 1, w[Id[i] ^ 1] += 1;
	return Dijkstra();
}

signed main()
{
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(0);

	memset(h, -1, sizeof h);

	cin >> N >> M >> L >> S >> T;

	int u, v, c, Cpy = M;
	while (M --)
	{
		cin >> u >> v >> c;
		if (c) add(u, v, c), add(v, u, c);
		else
		{
			Id.push_back(idx), add(u, v, 1);
			Id.push_back(idx), add(v, u, 1);
		}
	}
	M = Cpy;

	if (!Id.size())
	{
		if (Dijkstra() == L)
		{
			cout << "YES" << endl;
			for (int i = 0; i < idx; i += 2)
				cout << e[i ^ 1] << " " << e[i] << " " << w[i] << endl;
		}
		else
			cout << "NO" << endl;
		return 0;
	}

	int l = Id.size() / 2, r = L * M;
	while (l < r)
	{
		int mid = l + r >> 1;
		if (Check(mid) >= L) r = mid;
		else l = mid + 1;
	}

	if (Check(r) != L)
	{
		cout << "NO" << endl;
		return 0;
	}

	cout << "YES" << endl;
	for (int i = 0; i < idx; i += 2)
		cout << e[i ^ 1] << " " << e[i] << " " << w[i] << endl;

	return 0;
}

W a y   2 \mathrm{Way\ 2} Way 2

S S S 开始先做 1 1 1Dijkstra,记当前 L L L S S S T T T 的最短路的差值为 D i f f Diff Diff(即 D i f f = L − D 1 , T Diff=L-D_{1,T} Diff=LD1,T

之后再做第 2 2 2Dijkstra 的时候,当点 u u u 更新至点 v v v 时且当前边为特殊边(初始变为 0 0 0),若 D 2 , u + w i < D 1 , v + D i f f D_{2,u}+w_i< D_{1,v}+Diff D2,u+wi<D1,v+Diff,则说明这时候最短路长度少了,尽量要让其补上这缺失的部分,即 w i = D 1 , u + D i f f − D 2 , u w_i = D_{1,u}+Diff-D_{2,u} wi=D1,u+DiffD2,u。修改后,再进行正常 Dijkstra 的更新即可。

注:
D 1 , i D_{1,i} D1,i 表示第 1 1 1Dijkstra 到达 i i i 号点的最短路长度, D 2 , i D_{2,i} D2,i 表示第 2 2 2Dijkstra 到达第 i i i 号点的最短路长度。

C o d e Code Code

#include <bits/stdc++.h>
#define int long long

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

const int SIZE = 2e4 + 10;

int N, M, L, S, T;
int h[SIZE], e[SIZE], ne[SIZE], w[SIZE], f[SIZE], idx;
int D[2][SIZE], Vis[SIZE];

void add(int a, int b, int c)
{
	if (!c) f[idx] = 1;
	e[idx] = b, ne[idx] = h[a], w[idx] = max(1ll, c), h[a] = idx ++;
}

void Dijkstra(int dist[], int Turn)
{
	for (int i = 0; i < N; i ++)
		dist[i] = 1e18, Vis[i] = 0;
	priority_queue<PII, vector<PII>, greater<PII>> Heap;
	Heap.push({0, S}), dist[S] = 0;

	while (Heap.size())
	{
		auto Tmp = Heap.top();
		Heap.pop();

		int u = Tmp.second;
		if (Vis[u]) continue;
		Vis[u] = 1;

		for (int i = h[u]; ~i; i = ne[i])
		{
			int j = e[i];
			if (Turn == 2 && f[i] && dist[u] + w[i] < D[0][j] + L - D[0][T])
				w[i] = w[i ^ 1] = D[0][j] + L - D[0][T] - dist[u];
			if (dist[j] > dist[u] + w[i])
			{
				dist[j] = dist[u] + w[i];
				Heap.push({dist[j], j});
			}
		}
	}
}

signed main()
{
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(0);

	memset(h, -1, sizeof h);

	cin >> N >> M >> L >> S >> T;

	int u, v, c;
	while (M --)
	{
		cin >> u >> v >> c;
		add(u, v, c), add(v, u, c);
	}

	Dijkstra(D[0], 1);
	if (L - D[0][T] < 0)
	{
		cout << "NO" << endl;
		return 0;
	}
	Dijkstra(D[1], 2);

	if (D[1][T] != L)
	{
		cout << "NO" << endl;
		return 0;
	}

	cout << "YES" << endl;
	for (int i = 0; i < idx; i += 2)
		cout << e[i ^ 1] << " " << e[i] << " " << w[i] << endl;

	return 0;
}

http://www.niftyadmin.cn/n/5383861.html

相关文章

机器人内部传感器阅读笔记及心得-位置传感器-光电编码器

目前&#xff0c;机器人系统中应用的位置传感器一般为光电编码器。光电编码器是一种应用广泛的位置传感器&#xff0c;其分辨率完全能满足机器人的技术要求&#xff0c;这种非接触型位置传感器可分为绝对型光电编码器和相对型光电编码器。前者只要将电源加到用这种传感器的机电…

SICTF Round#3 Web方向 题解WP

100&#xff05;_upload 题目描述&#xff1a;小茂夫说&#xff1a;一直上传恶意文件尊嘟要生气了&#xff0c;世事莫固守&#xff0c;转变思路求突破 开题&#xff0c;注意有个文件包含 题目把后缀过滤死了&#xff0c;无法上传php后缀文件。文件内容些许过滤&#xff0c;短…

Vue中$route 和$router 的区别

在Vue的前端开发中&#xff0c;经常会涉及到路由的使用。Vue提供了两个重要的对象来处理路由相关的操作&#xff0c;即 r o u t e 和 route和 route和router。虽然它们的名字相似&#xff0c;但是它们的作用和使用方式却有一些不同。 首先&#xff0c;让我们来看一下 r o u t …

【JGit】分支管理实践

本文紧接【JGit】简述及学习资料整理。 以下梳理了使用 JGit 进行 Git 操作的实践 JGit实践 主函数 public static void main(String[] args) throws Exception {String localDir "D:\\tmp\\git-test\\";String gitUrl "http://192.168.181.1:3000/root/g…

C++题目打卡2.18

从今天开始我们又将讲4天题目。 题目列表 1.分配T4 2.组合T5 #分配T4 这里很明显是&#xff08;200 110&#xff09; - 330的差值最小。 我们先想到了一个想法就是输入时哪个堆大,加那个。 #include <bits/stdc.h> using namespace std; int main(){int n, ans1 0, …

安卓OpenGL添加水印并录制(二)---抖音录制原理

文章目录 前文回顾音频处理留个小思考总结 本文首发地址 https://h89.cn/archives/146.html 最新更新地址 https://gitee.com/chenjim/chenjimblog 源码地址: Gitee: OpenGLRecorder 通过 前文 我们知道了如何采集 Camera 视频&#xff0c;叠加水印、贴纸保存为MP4&#xff0c;…

云数贸云生活中心:用云生活理念引领社会和谐发展

在数字经济的浪潮下&#xff0c;云数贸云生活中心不仅在科技进步与文明程度上作出了积极贡献&#xff0c;更在推动社会和谐、承担企业社会责任方面展现出了模范作用。通过与“草根互助爱心社区”的紧密合作&#xff0c;云数贸云生活中心正致力于构建一个更加和谐、互助的社会环…

FOC电流环速度环调试记录

FOC电流环速度环调试记录 电流环&#xff1a; 首先foc控制中都采用PI控制&#xff0c;没有引入微分&#xff0c;因为电流的采样率非常高不需要加入微分项&#xff1b;微分项的加入&#xff0c;会使电流采样中的高频小信号误差起到放大的作用&#xff0c;把小的误差放大&#…