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

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

题目大意:

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

解题思路:

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

猜你喜欢

转载自blog.csdn.net/Scar_Halo/article/details/83548304
今日推荐