首页 > 其他分享 >[学习笔记]分层图最短路

[学习笔记]分层图最短路

时间:2023-12-08 23:23:04浏览次数:35  
标签:nowk int 短路 笔记 Queue 分层 num define dis

分层图的概念

分层图最短路,听名字就知道他和其他最短路不一样,实际也确实如此,可以解决一些普通最短路无法解决的问题。

比如有 \(n\) 个点 \(m\) 条带权无向边,可以将 \(k\) 条边进行某些操作,然后求出从 \(1\) 到 \(n\) 的最短路,此时即可使用分层图。

例题

例题 1 P4568 [JLOI2011] 飞行路线

P4568 [JLOI2011] 飞行路线

简化题意

有 \(n\) 个点 \(m\) 条带权无向边,可以将 \(k\) 条边的边权变为 \(0\),求从 \(s\) 到 \(t\) 的最短路。

分析

这就是开头所说的例子,设 \(dis_{i, j}\) 为将 \(j\) 条边的边权变为 \(0\) 的情况的最短路,然后正常跑 dijkstra,

答案为 \(\sum\limits_{i=1}^{k}\min(dis_{t, i})\)。

AC 代码

/*Code By Manipula*/
#include <bits/stdc++.h>
// #define Fileopen
#pragma GCC optimize(2)
#define INF 0x3f3f3f3f
#define int long long
#define swap(x, y) x ^= y ^= x ^= y
#define sqrt(n) pow(n, 0.5)
#define sort stable_sort
#define mk(x, y) make_pair(x, y)
#define mst(arr, num) memset(arr, num, sizeof(arr))
#define endl '\n'
using namespace std;
const int N = 1e4 + 5;
struct Edge{
	int v, w, nxt;
}edge[N * 10];
struct Queue{
	int u, k, w;
	bool operator < (const Queue a) const{
		return w > a. w;
	}
};
priority_queue<Queue> q;
int head[N], dis[N][15], vis[N][15];
int n, m, num, k, ans = INF;
void add(int u, int v, int w){edge[++num] = (Edge){v, w, head[u]}; head[u] = num;}
void dijkstra(int s)
{
	mst(dis, INF);
	dis[s][0] = 0; q.push((Queue){s, 0, 0});
	while (!q.empty())
	{
		int u = q.top().u, nowk = q.top().k; q.pop();
		if (vis[u][nowk])continue; vis[u][nowk] = 1;
		for (int i = head[u]; i; i = edge[i].nxt)
		{
			int v = edge[i].v, w = edge[i].w;
			if (nowk < k && dis[v][nowk + 1] > dis[u][nowk])
			{
				dis[v][nowk + 1] = dis[u][nowk];
				q.push((Queue){v, nowk + 1, dis[v][nowk + 1]});
			}
			if (dis[v][nowk] > dis[u][nowk] + w)
			{
				dis[v][nowk] = dis[u][nowk] + w;
				q.push((Queue){v, nowk, dis[v][nowk]});
			}
		}
	}
}
signed main()
{
	#ifdef Fileopen
		freopen(".in", r, stdin);
		freopen(".out", w, stdout);
	#endif
	int s, t;
	cin >> n >> m >> k >> s >> t;
	for (int i = 1, u, v, w; i <= m; i++)
	{
		cin >> u >> v >> w;
		add(u, v, w); add(v, u, w);
	}
	dijkstra(s);
	for (int i = 0; i <= k; i++)ans = min(ans, dis[t][i]);
	cout << ans;
	return 0;
}

例题 2 P4822 [BJWC2012] 冻结

P4822 [BJWC2012] 冻结

简化题意

有 \(n\) 个点 \(m\) 条带权无向边,可以将 \(k\) 条边的边权变为原来的一半,求从 \(1\) 到 \(n\) 的最短路。

分析

与上一题的想法大致是一样的,只不过上一题的变为 \(0\) 变成了变为原来的一半,总体代码差不多,但仍然给一下代码。

AC 代码

/*Code By Manipula*/
#include <bits/stdc++.h>
// #define Fileopen
#pragma GCC optimize(2)
#define INF 0x3f3f3f3f
#define int long long
#define swap(x, y) x ^= y ^= x ^= y
#define sqrt(n) pow(n, 0.5)
#define sort stable_sort
#define mk(x, y) make_pair(x, y)
#define mst(arr, num) memset(arr, num, sizeof(arr))
#define endl '\n'
using namespace std;
const int N = 1e4 + 5;
struct Edge{
	int v, w, nxt;
}edge[N * 10];
struct Queue{
	int u, k, w;
	bool operator < (const Queue a) const{
		return w > a. w;
	}
};
priority_queue<Queue> q;
int head[N], dis[N][55], vis[N][55];
int n, m, num, k, ans = INF;
void add(int u, int v, int w){edge[++num] = (Edge){v, w, head[u]}; head[u] = num;}
void dijkstra(int s)
{
	mst(dis, INF);
	dis[s][0] = 0; q.push((Queue){s, 0, 0});
	while (!q.empty())
	{
		int u = q.top().u, nowk = q.top().k; q.pop();
		if (vis[u][nowk])continue; vis[u][nowk] = 1;
		for (int i = head[u]; i; i = edge[i].nxt)
		{
			int v = edge[i].v, w = edge[i].w;
			if (nowk < k && dis[v][nowk + 1] > dis[u][nowk] + w / 2)
			{
				dis[v][nowk + 1] = dis[u][nowk] + w / 2;
				q.push((Queue){v, nowk + 1, dis[v][nowk + 1]});
			}
			if (dis[v][nowk] > dis[u][nowk] + w)
			{
				dis[v][nowk] = dis[u][nowk] + w;
				q.push((Queue){v, nowk, dis[v][nowk]});
			}
		}
	}
}
signed main()
{
	#ifdef Fileopen
		freopen(".in", r, stdin);
		freopen(".out", w, stdout);
	#endif
	cin >> n >> m >> k;
	for (int i = 1, u, v, w; i <= m; i++)
	{
		cin >> u >> v >> w;
		add(u, v, w); add(v, u, w);
	}
	dijkstra(1);
	for (int i = 0; i <= k; i++)ans = min(ans, dis[n][i]);
	cout << ans;
	return 0;
}

标签:nowk,int,短路,笔记,Queue,分层,num,define,dis
From: https://www.cnblogs.com/Manipula/p/17889264.html

相关文章

  • CSS笔记
    1.CSS选择器是用于选取HTML文档中的元素的一种方式。常见的选择器包括:元素选择器:通过元素的标签名来选取元素,例如p、div等。类选择器:通过元素的class属性来选取元素,使用.符号加上类名,例如.my-class。ID选择器:通过元素的id属性来选取元素,使用#符号加上id值,例如#my-id。属性选......
  • JavaScript笔记
    JavaScript的组成:     1.数据类型:JavaScript有8种基本数据类型,包括Undefined、Null、Boolean、Number、String、BigInt、Symbol和Object。变量:在JavaScript中,可以使用var、let或const关键字声明变量。函数:JavaScript中的函数是一种可重用的代码块,可以使用fun......
  • 软件构造笔记
    今天软件构造考试结束了,这门课真的上的听玄幻的主要通过对ppt的整理得到的笔记格式是word里的格式,有原件和ppt,但是不方便直接发  有重构的书pdf软件构造前言l 推荐书目代码大全 代码整洁之道  重构改善既有代码设计l 主要都是ppt里的  合肥工业大学张高峰......
  • 【CCFCSP】2209真题笔记
    -1.如此编码分析daisuki代数题了,直接无脑套公式子任务有提示,记得参考测试数据:1532767222222222222222预期结果:111111111111111AC:#include<iostream>usingnamespacestd;constintmaxn=25;intn,m,tmp;inta[maxn],b[maxn];......
  • 第二周阅读笔记|人月神话
    9.23阅读了贵族专制、民主政治和系统设计我发现这个作者写的还是蛮通俗易懂的,而且有点引经据典的味道,读着还蛮津津有味的。功能,而非简洁,总是被用来衡量设计人员工作的出色程度。这是错的,任何事情我们都应该从他的实用性出发,拒绝假大空。因此,易用性实际上需要设计的一致性和概念......
  • HTML笔记
    1.什么是HTMl:HTML(HyperTextMarkupLanguage)是一种用于创建网页的标准标记语言。它使用一系列标签来定义网页的结构、内容和样式。HTML文档由一系列的元素组成,这些元素包括标题、段落、链接、图片、列表等。通过使用HTML标签,开发者可以创建出具有交互性和动态效果的网页。2.HTML......
  • 二分——acwing算法基础课笔记
    个人笔记,欢迎补充、指正。此次完全以个人理解来写。整数二分 整数二分有两种,分别是找左边界和找右边界。 寻找符合要求的左边界:绿色点intbsearch_1(intl,intr){while(l<r){intmid=l+r>>1;//对应下界,最左if(check(mid))r=......
  • 最短路径
    #include<iostream>#include<cstring>#include<cstdio>usingnamespacestd;constintN=1010;structedge{intv,w;edge*next;};structnode{intk;edge*next;}a[1010];intn;intfind(intu){for(inti=0;i<n;i++){if(a......
  • 秦疆的Java课程笔记:64 面向对象 构造器详解
    类中的构造器也称为构造方法,世在进行创建对象的时候必须要调用的。并且构造器有以下两个特点必须和类的名字相同必须没有返回类型,也不能写void构造器必须掌握!一个类即使什么也没写,也会存在一个方法//写一个空的Person类=========================publicclassPer......
  • <学习笔记> 二项式反演
    容斥原理容斥原理的式子\[|A1∪A2∪...∪An|=\sum_{1≤i≤n}|Ai|−\sum_{1≤i<j≤n}|Ai∩Aj|+...+(−1)^{n−1}×|A1∩A2∩...∩An|\]一般来说不会直接用容斥原理这个式子,而是考虑一种特殊情况:交集的大小只与交集的数量有关。也就是说,我们可以用$f[x]$来表示\(n\)个集合的......