首页 > 其他分享 >最短路题型

最短路题型

时间:2022-12-10 21:57:12浏览次数:58  
标签:pre 题型 短路 路径 pair 节点 dis

类型

一.稍微变形的模板

例:1.P1576 最小花费
松弛操作改了一点点。

点击查看代码
if(dis[v]>dis[u]/(1-0.01*w)){
    dis[v]=dis[u]/(1-0.01*w);
    q.push(make_pair(dis[v],v));
}

2.P3905 道路重建
把好路的边权设置为0。然后跑最短路就行了。

3.P1342 请柬
正反各一遍最短路(好多题都是这个套路,关键是想出来)。

二.最短路径树

这篇博客讲的不错:最短路径树
还是口胡一下吧。如果讲的哪里有问题,欢迎指出,感谢。

概念

在一张无向边带权图的基础上,构建一棵树,使根节点到树上任意节点的距离都是原图中根节点到该点的最短路。

原理

(即建树原理),一个点到根节点的最短路一定由其他点到根节点的最短路或者直接由根转移过来的。所以一张图就这样构成一棵树了。

操作

与单源最短路模板相比,每个点有一个前继节点,只需在松弛的时候根据题意更换前继节点,就像这样。

点击查看代码
if(dis[v]>dis[u]+w){
    dis[v]=dis[u]+w;
    pre[v]=u;
    q.push(make_pair(dis[v],v));
}else if(dis[v]==dis[u]+w){
	if(pre[v]>u) pre[v]=u;
}
发现多出来的就是 else if 那段,那段可以根据题意适时维护。

例:
1.Paths and Trees
要求边权和最小的最短路径树,即使得该最短路径树的边权和最小。
假设有两条到 \(v\) 的最短路,但是直接和 \(v\) 相连的边权不一样,该找哪一条呢?如果听不明白,这有张图。

可以看出选连接 \(v\) 的边权最小的那条边。于是 else if 里的那一段就可以写出来了。
核心代码:

点击查看代码
if(dis[v]>dis[u]+w){
    dis[v]=dis[u]+w;
    pre_edge[v]=id;
    pre_dis[v]=w;
    q.push(make_pair(dis[v],v));
}else if(dis[v]==dis[u]+w&&pre_dis[v]>w){
    pre_edge[v]=id;
    pre_dis[v]=w;
}
再来看一道例题。

2.P5201 [USACO19JAN]Shortcut G
题意:给定一个有 \(n\) 个结点和 \(m\) 条边的带权无向图,每个结点 \(i\) 上有 \(c_i\) 头奶牛,\(1\)号结点为家,每次回家奶牛会走一条最短的路径,如果有多条长度相同的最短路径,则奶牛会走字典序最小的一条。现在,你可以增加一条从\(1\)到任意结点的长度为给定值 \(T\) 的一条边。如果一头奶牛在平时回家的路上经过了这条边相连的结点,且这条边能使其回家路径更短,则其会走这条边。求能使所有奶牛走的路径长度和的变化的最大值。(来自hsfzLZH1大佬的概括)
思路:可以发现,需要将每个节点上的奶牛到根走的路径求出来,然后枚举要在哪个点建立路径。
可以将以\(1\)为根的最短路径树建出来,这是一棵什么样的最短路径树呢?
我不会说,核心代码:

点击查看代码
if(dis[v]>dis[u]+w){
    dis[v]=dis[u]+w;
    pre[v]=u;
    q.push(make_pair(dis[v],v));
}else if(dis[v]==dis[u]+w){
    if(pre[v]>u) pre[v]=u;//因为要走字典序最小的路径,所以当之前确定的点大于现在可以松弛的点时,说明就得替换前继节点。
}
这样每个节点的奶牛到跟走的路径就可以确定了。然后枚举枚举要在哪个点建立路径。 核心代码:
点击查看代码
for(int i=2;i<=n;i++) 
    ans=max(ans,1ll*(dis[i]-t)*siz[i]);

剩下一道例题(可以自己去看看):Berland and the Shortest Paths
大概总结一下:其实核心部分还是找前继节点(也就是 else if 那一段),根据题目要求建树就好了。

三.分层图

关于讲解:楠不会(依旧引荐其他大佬的博客)分层图
例题:1.P4568 [JLOI2011] 飞行路线
可以发现 \(k\) 很小,\(n\) 也不大,我们可以建20层一模一样的图,在每一层之间建免费的边。这样最多使用20次免费的机会,也就是20层,跑最短路即可。

点击查看代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#define pii pair<long long,int>
using namespace std;
vector<pii> g[200005];
priority_queue<pii,vector<pii>,greater<pii> > q;
int n,m,k,s,t;
bool vis[200005];
long long v[200005];
long long minn=0x7fffffff;
void dij(int s){
	v[s]=0;
	q.push(make_pair(v[s],s));
	while(!q.empty()){
		int u=q.top().second;
	    q.pop();
	    if(vis[u]){
	    	continue;
	    }
	    vis[u]=1;
		for(int i=0;i<g[u].size();i++){
			int uu=g[u][i].second;
			int vv=g[u][i].first;
			if(vis[uu]) continue;
			if(v[uu]>v[u]+vv){
				v[uu]=v[u]+vv;
				q.push(make_pair(v[uu],uu));
			}
		}
	}
}
int main(){
	cin>>n>>m>>k>>s>>t;
	for(int i=0;i<=n*(k+1);i++){
		v[i]=0x7fffffff;
	}
	for(int i=1;i<=m;i++){
		int from,to,dis;
		cin>>from>>to>>dis;
		g[from].push_back(make_pair(dis,to));
		g[to].push_back(make_pair(dis,from));
		for(int j=1;j<=k;j++){
			g[from+j*n].push_back(make_pair(dis,to+j*n));
			g[to+j*n].push_back(make_pair(dis,from+j*n));
			g[from+(j-1)*n].push_back(make_pair(0,to+j*n));
			g[to+(j-1)*n].push_back(make_pair(0,from+j*n));
		}
	}
	dij(s);
	for(int i=0;i<=k;i++){
		minn=min(minn,v[t+i*n]);
	}
	cout<<minn;
	return 0;
}

三倍经验:
P4822 [BJWC2012]冻结
P2939 [USACO09FEB]Revamping Trails G

四.线段树优化建图

Legacy
题意:一张有向边带权图,三种操作:
操作1:从 \(u\) 到 \(v\) 连一条长度为 \(w\)的边。
操作2: 从 \(v\) 向 \([l,r]\) 这个区间内的点连长度为 \(w\) 的边。
操作3:从 \([l,r]\) 这个区间内的点向 \(v\) 连长度为 \(w\) 的边。
最后求 \(s\) 到其他点的最短路长度。
emm...先鸽了吧。

标签:pre,题型,短路,路径,pair,节点,dis
From: https://www.cnblogs.com/Travller/p/16972413.html

相关文章

  • 经过指定点的最短路径
    题目描述:给出一个有n个顶点的有向网,指定其中k个顶点(不含顶点1和顶点n),求从顶点1到顶点n的,经过那k个顶点的最短路。输入:第一行是顶点数n和弧数目e。......
  • 迪杰斯特拉方法实现最短路径
    用迪杰斯特拉算法实现有向网的最短路径输入格式:第一行输入有向网的顶点和边数,第二行输入各顶点值,用空格间隔,第三行开始输入各条边的两个点的及边上的权值,用空格间隔。......
  • poj3255 Roadblocks--次短路spfa
    原题链接:​​http://poj.org/problem?id=3255​​题意:n个点,标号为1到n,m条路,u,v,len,表示u与v之间路长为len,求1到n第二短路长,题目保证存在第二短路径。#define_CRT_SECURE_NO_D......
  • 最短路
    最短路记号约定\(n\)是点数,\(m\)是边数。\(s\)是源点。\(D\left(u\right)\)是从\(s\)点到\(u\)点的实际最短路,\(D\left(u,v\right)\)是从\(u\)点到\(v\)点的实际最短路......
  • 经典算法——最短路径(Floyd+Dijkstra)
    Floyd时间复杂度:O(n^3)简介:作为最短路算法中复杂度最高的算法没有之一,标志性结构三层循环,核心结构本质DP思想具 有动态规划的无后效性他真的没有优点啦?!不,他有!虽然SPF......
  • 最短路算法及其常见扩展应用
    第一节——最短路问题基本概念:由于无向边可以看作两条相反的有向边,于是我们默然按照有向边的形式讨论存图方式:邻接矩阵:空间复杂度\(O(n^2)\),优点:\(O(1)\)查找\(x->y\)......
  • 最短路径Dijkstra算法
    最短路径最短路径的性质:路径是有向的权重不一定等价于距离,权重也可以指时间,花费或者其他并不是所有顶点都是可达的负权重会使得问题更复杂(Dijkstra算法不适用于......
  • 函数的使用 + 函数的表达式 +函数的返回值 + 函数中的细节 + 作用域 + 变量的特
    函数:就是封装重复执行的代码块function是声明函数的关键字必须小写函数命名一般为动词函数声明必须调用否则不生效(调用要加小括号())函数封装就是把一个或者多个功能......
  • Floyd算法(最短路径)
    Floyd算法允许图中有带负权值的边,但不许有包含带负权值的边组成的回路。     上一篇文章我们通过迪杰斯特拉算法解决了从某个源点到其余各顶点的最短路径问题。从循......
  • 贪心算法篇——经典题型
    贪心算法篇——经典题型本次我们介绍贪心算法篇的经典题型,我们会从下面几个角度来介绍:Huffman树排序不等式绝对值不等式推公式Huffman树我们直接给出对应题型:/*......