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

这篇具有很好参考价值的文章主要介绍了【图论经典题目讲解】CF715B - Complete The Graph。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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} CF715B−Complete 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 号点的最短路长度。文章来源地址https://www.toymoban.com/news/detail-827351.html

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;
}

到了这里,关于【图论经典题目讲解】CF715B - Complete The Graph的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【*1900 图论】CF1328 E

    Problem - E - Codeforces 题意: 思路: 注意到题目的性质:满足条件的路径个数是极少的,因为每个点离路径的距离 =1 先考虑一条链,那么直接就选最深那个点作为端点即可 为什么,因为我们需要遍历所有点的父亲 推广到树,也是要遍历所有点的父亲 为什么要加枚举的tag,因为

    2024年02月15日
    浏览(8)
  • 【简单图论】CF1833 E

    Problem - E - Codeforces 题意:    思路: 显然,最大值就是什么边都不连的连通块个数,最小值就是能连的都连上 那就是,如果一个连通块存在度为1的点,就把它当作接口连接 Code:

    2024年02月16日
    浏览(8)
  • 【*1900 图论+枚举思想】CF1328 E

    Problem - E - Codeforces 题意: 思路: 注意到题目的性质:满足条件的路径个数是极少的,因为每个点离路径的距离 =1 先考虑一条链,那么直接就选最深那个点作为端点即可 为什么,因为我们需要遍历所有点的父亲 推广到树,也是要遍历所有点的父亲 为什么要加枚举的tag,因为

    2024年02月14日
    浏览(11)
  • 【简单图论】CF898 div4 H

    Problem - H - Codeforces 题意: 思路: 手玩一下样例就能发现简单结论: v 离它所在的树枝的根的距离 m 离这个根的距离时是 YES 否则就是NO 实现就很简单,先去树上找环,然后找出这个根,分别给a 和 b BFS一遍,得出两个dis数组,比较一下即可 对于只有的环情况 和 m = v 的情况需

    2024年02月07日
    浏览(10)
  • Graph Theory(图论)

    图是通过一组边相互连接的顶点的集合。     In this graph, V = { A , B , C , D , E } E = { AB , AC , BD , CD , DE } A graph consisting of finite number of vertices and edges is called as a finite graph.   Null Graph Trivial Graph Non-directed Graph Directed Graph Connected Graph Disconnected Graph Regular Graph Complete Graph Cycle Graph Cy

    2024年02月08日
    浏览(14)
  • 图论(Graph theory)

    Graphic操作接口 操作接口 功能描述 操作接口 功能描述 e() 获取图的总边数 n() 顶点的总数 exits(v,u) 判断v,u两个顶点是否存在边 insert(v) 在顶点集 V 中插入新顶点 v remove(v,u) 删除从v 到u的 关联边 remove(v) 将顶点 v 从顶点集中删除 type(v,u) 边所属的类型(主要用于遍历树~) inDegree(v

    2024年04月27日
    浏览(7)
  • CF1120 D. Power Tree 巧妙的图论转化

    传送门 [前题提要]:无 题目描述: 考虑对一个点的子树的所有 叶子节点 进行增减任意值.不难联想到对一个点的子树的 所有节点 增减任意值的做法.所以考虑使用类似于树链剖分的方式将树上修改化为链上区间修改. 考虑记录一个点的所有叶子节点,并且按照 d f s dfs df s 序将其

    2024年02月10日
    浏览(9)
  • DONE Build complete. The dist directory is ready to be deployed.

      npm run build   命令执行完出现  DONE  Build complete. The dist directory is ready to be deployed.  INFO  Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html 可以根据官方文档 目录需要启动一个 HTTP 服务器来访问 (除非你已经将  publicPath  配置为了一个相对的值),所以以  file

    2024年02月11日
    浏览(12)
  • FATAL Error: Unable to complete saved object migrations for the [.kibana_task_manager] index. Plea

    报错信息:         在启动Kibana时报了上述错误,在网上百度了好多帖子未找到答案。后来翻看了配置信息也没发现错误。想来想去是不是es启动时有问题呢?自己又重新启动了一下es,发现日志中竟然有错误,观看提示的英文错误,大致意思是磁盘占用率达到95%。删除了

    2024年02月12日
    浏览(28)
  • 算法题目题单+题解——图论

    本文为自己做的一部分图论题目,作为题单列出,持续更新。 题单由题目链接和题解两部分组成,题解部分提供简洁题意,代码仓库:Kaiser-Yang/OJProblems。 对于同一个一级标题下的题目,题目难度尽可能做到递增。 题目链接:Luogu P3547 [POI2013] CEN-Price List 题解: 题目链接:

    2024年02月19日
    浏览(7)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包