【图论】最短路的传送问题

一.分层图问题(单源传送)

(1)题目

P4568 [JLOI2011] 飞行路线 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

(2)思路

可知背景就是求最短路问题,但难点是可以使一条路距离缩短至0,那如何更好的利用这个机会呢?

此时我们可以用到分层图,如下:

即我们可以免费往下传一次,其实也就相当于两点距离为0了,这时终点应该9号节点。

于是建图如下:

cpp 复制代码
			add(u+(j-1)*n,v+j*n,0);
			add(v+(j-1)*n,u+j*n,0);
			add(u+j*n,v+j*n,w);
			add(v+j*n,u+j*n,w);

第一个是从上到下,是使用传送的边

第二个是第一个的逆向

第三个是已经用过一次机会,已经在下面了,所以正常边

第四个是第三个的逆向

cpp 复制代码
	for(int j=1;j<=k;j++){
		add(s+(j-1)*n,s+j*n,0);
	}

这个是特殊情况,起点即终点,一路传送,其实多此一举,但没办法,只怪我们把图分层了。不能在自环到达了。

(3)参考代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n,m,k;
int s,e;
struct Edge{
	int u,v,w,next;
}edge[2500001];
int head[110005],cnt;
void add(int u,int v,int w){
	edge[++cnt]=(Edge){u,v,w,head[u]}; head[u]=cnt;
}
int dis[110005],vis[110005];
struct node{
	int u,w;
	bool operator < (const node &x) const{
		return x.w<w;
	}
};
void dijkstra(){
	priority_queue<node>q;
	memset(dis,0x3f,sizeof(dis));
	q.push((node){s,0});
	dis[s]=0;
	while(!q.empty()){
		node temp=q.top(); q.pop();
		int u=temp.u;
		if(vis[u]) continue;
		vis[u]=1;
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				q.push((node){v,dis[v]});
			}
		}
	}
}
int main(){
	cin>>n>>m>>k>>s>>e;
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		add(u,v,w);add(v,u,w);
		for(int j=1;j<=k;j++){
			add(u+(j-1)*n,v+j*n,0);
			add(v+(j-1)*n,u+j*n,0);
			add(u+j*n,v+j*n,w);
			add(v+j*n,u+j*n,w);
		}
	}
	for(int j=1;j<=k;j++){
		add(s+(j-1)*n,s+j*n,0);
	}
	dijkstra();
	cout<<dis[e+k*n];
	return 0;
}

二.多源传送

(1)题目

P6464 [传智杯 #2 决赛] 传送门 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

(2)思路

这题虽然是多源,但只有一个传送门,而且数据范围小,只有100,所以直接上floyd算法!

因为我们不知道传送门怎么建立,所以直接暴力枚举就行了。

我们两重遍历,找出门,在两重暴力folyd即可。

Q:folyd不是三重吗?

A:不是已经知道在哪搭桥了吗?

Q:其他不也可以搭桥吗?

A:前面的预处理三重floyd已经处理好了。

(3)参考代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
int f[101][101];
int F[101][101];
inline void back()
{
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			F[i][j]=f[i][j];
}
int main()
{
	scanf("%d%d",&n,&m);
	memset(f,-1,sizeof(f));
	for(int i=1;i<=m;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		if(f[u][v]==-1||f[u][v]>w)	f[u][v]=f[v][u]=w;//建边,防重边(不过数据里没有)
	}
	for(int k=1;k<=n;k++)	
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				if(f[i][k]!=-1&&f[k][j]!=-1)
					if(f[i][j]==-1||f[i][j]>f[k][j]+f[i][k])
						f[i][j]=f[i][k]+f[k][j];//Floyd
	int ans=2e9;//较大值
	for(int i=1;i<=n;i++)	
		for(int j=1;j<=n;j++)//暴力枚举
		{
			back();//先让F数组还原成f数组
			F[i][j]=F[j][i]=0;//在教学楼 i 和 j 之间建立传送门
			//i点搭桥 
			for(int x=1;x<=n;x++)	
				for(int y=1;y<=n;y++)	
					if(F[x][y]==-1||F[x][y]>F[x][i]+F[i][y])
						F[x][y]=F[x][i]+F[i][y];//Floyd
			//j点搭桥 
			for(int x=1;x<=n;x++)
				for(int y=1;y<=n;y++)	
					if(F[x][y]==-1||F[x][y]>F[x][j]+F[j][y])
						F[x][y]=F[x][j]+F[j][y];//Floyd
			int res=0;
			for(int x=1;x<=n;x++)	
				for(int y=1;y<x;y++)
					res+=F[x][y];
			ans=min(res,ans);
		}
	printf("%d\n",ans);
	return 0;
}
相关推荐
CodeWizard~1 天前
AtCoder Beginner Contest 430赛后补题
c++·算法·图论
天选之女wow2 天前
【代码随想录算法训练营——Day58】图论——117.软件构建、47. 参加科学大会
算法·图论
earthzhang20213 天前
【2051】【例3.1】偶数
开发语言·数据结构·算法·青少年编程·图论
apcipot_rain3 天前
CSP集训错题集 第八周 主题:基础图论
算法·图论
天选之女wow3 天前
【代码随想录算法训练营——Day57(Day56周日休息)】图论——53.寻宝
算法·图论
极客数模3 天前
2025年(第六届)“大湾区杯”粤港澳金融数学建模竞赛准备!严格遵循要求,拿下大奖!
大数据·python·数学建模·金融·分类·图论·boosting
岑梓铭4 天前
《考研408数据结构》第七章(6.1~6.3图的概念、存储方式、深/广度遍历)复习笔记
数据结构·笔记·考研·算法·图论·408·ds
天选之女wow4 天前
【代码随想录算法训练营——Day53】图论——110.字符串接龙、105.有向图的完全可达性、106.岛屿的周长
算法·深度优先·图论
武子康4 天前
Java-165 Neo4j 图论详解 欧拉路径与欧拉回路 10 分钟跑通:Python NetworkX 判定实战
java·数据库·性能优化·系统架构·nosql·neo4j·图论
极客数模5 天前
【浅析赛题,一等奖水平】思路模型数据相关资料!2025 年“大湾区杯”粤港澳金融数学建模竞赛B 题 稳定币的综合评价与发展分析~
大数据·算法·数学建模·金融·数据挖掘·图论·1024程序员节