HDU-4725___The Shortest Path in Nya Graph —— 拆点 + 最短路

题目链接:点我啊╭(╯^╰)╮

题目大意:

    最短路的模板题,问题是多了一个条件,就是每个点都属于一个层(可能有多个点属于同一层),相邻层之间的所有点都可以以距离 C C C到达,问 1 1 1 n n n的最短距离???

解题思路:

    关键在于处于层与层之间的边的问题,如果全部直接建边,边数为 N 2 N^2 N2,明显会超时
    那么用什么办法来减少边数呢?这里可以联想并查集里的虚拟父节点,对每一层都创建一个虚拟节点,通过该虚拟节点处理层与层的关系,则我们只需要连接该层的结点与其虚拟节点 和 虚拟节点与相邻层的结点 即可,边数为 2 C 2C 2C
    建边规则:
①:该层的所有节点指向该层的虚拟节点——权值为 0 0 0
②:第 i i i层的虚拟节点指向第 i + 1 i+1 i+1层的所有节点——权值为 C C C
③:第 i + 1 i+1 i+1层的虚拟节点指向第 i i i层的所有节点——权值为 C C C

PS:也有其他的建边方法,重点是不能将同一层的虚拟节点与其节点建立无向边!

代码思路:

    SPFA或Dijkstra堆优化

核心:用虚拟节点减少边数从而优化

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
 
const int MAXN = 300010;
const int MAXM = 700010;
const int ANS_MAX = 2147483647;
 
struct EDGE {
	int next;
	int to;
	ll w;
} edge[MAXM];
 
int n, m, k, st, ed, cnt;
int head[MAXN], a[MAXN];
ll dis[MAXN];
bool vis[MAXN];
queue<int> Q;
 
inline int Read() {  //读入优化 可忽略 
	char c;
	int ans = 0;
	bool Sign = false;
	while(!isdigit(c=getchar()) && c != '-');
	if(c == '-') {Sign = true;c = getchar();}
	do {ans = (ans<<3) + (ans<<1) + (c - '0');} 
	while(isdigit(c=getchar()));
	return Sign ? -ans : ans;
}
 
void Add(int u, int v, ll w) {
	edge[++cnt].next = head[u];
	edge[cnt].to = v;
	edge[cnt].w = w;
	head[u] = cnt;
}
 
void read() {
	int x, y, l;
	ll w;
	n = Read();
	m = Read();
	k = Read();
	for(int i=1; i<=n; i++) {
		l = Read();
		a[i] = l;
		Add(i, a[i]+n, 0);
		if(l!=1) Add(a[i]+n-1, i, k);
		if(l!=n) Add(a[i]+n+1, i, k);
	}
	for(int i=1; i<=m; i++) {
		x = Read();
		y = Read();
		w = Read();
		Add(x, y, w);
		Add(y, x, w);
	}
}
 
bool SPFA(int x) {
	while(!Q.empty()) Q.pop();
	for(int i=1; i<=2*n; i++) dis[i] = ANS_MAX;
	dis[x] = 0;
	Q.push(x);
	vis[x] = true;
	while(!Q.empty()) {
		int k = Q.front();
		Q.pop();
		vis[k] = false;
		if(dis[k] == ANS_MAX) continue;
		for(int i=head[k]; i!=0; i=edge[i].next) {
			int j = edge[i].to;
			if(dis[j] > dis[k] + edge[i].w) {
				dis[j] = dis[k] + edge[i].w;
				if(!vis[j]) {
					Q.push(j);
					vis[j] = true;
				}
			}
		}
	}
	return 0;
}
 
int main() {
	int cas, t=1;
	cas = Read();
	while(cas--){
		memset(vis, 0, sizeof(vis));
		memset(head, 0, sizeof(head));
		cnt = 0;
		read();
		SPFA(1);
		printf("Case #%d: %d\n", t++, dis[n]==ANS_MAX?-1:dis[n]);
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值