[CF1473E]Minimum Path【分层图最短路】【dijkstra】

>Link

luogu CF1473E


>Description

给出一张 n n n 个点 m m m 条边的无向图
规定最短路的定义为:这条路径上的权值之和,减去最大权值,加上最小权值
1 1 1 到其他所有的点的最短路

n , m ≤ 2 ∗ 1 0 5 n,m\le 2*10^5 n,m2105


>解题思路

这种在一条路上对路径的权值操作的,想到分层图最短路
考虑最大权值、最小权值怎么搞,发现题意等同于「这条路径上的权值之和,减去一条边的权值,加上一条边权值」,因为这样求最短路,最优的情况肯定是「减去最大权值,加上最小权值」
那我们就把点分成三层,第一层到第二层建权值为 0 的边,表示减去这条边的权值,第二层到第三层建权值为 2 ∗ w 2*w 2w 的边,表示加上这条边的权值。每层内仍然正常建边
然后跑第一层的 1 到第三层的最短路

但是发现这样还是不行,因为这样建图就默认了这条路径的最大值在最小值的前面,还有最大值在最小值的后面的情况
那就第一层和第二层之间、第二层和第三层之间反着建,再跑一次就行了


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 600010
#define LL long long
using namespace std;

struct node
{
    
    
	int id; LL ds;
	friend bool operator < (node aa, node bb)
	{
    
    
		return aa.ds > bb.ds;
	}
};
priority_queue<node> Q;
struct edge
{
    
    
	int to, nxt; LL w;
} e[2000010];
int n, m, cnt, h[N], U[N], V[N];
LL dis[N], ans[N], W[N];
bool vis[N];

void add (int u, int v, LL w)
{
    
    
	e[++cnt] = (edge){
    
    v, h[u], w};
	h[u] = cnt;
//	e[++cnt] = (edge){u, h[v], w};
//	h[v] = cnt;
}
void dij ()
{
    
    
	node u; int v;
	memset (dis, 0x7f, sizeof (dis));
	memset (vis, 0, sizeof (vis));
	Q.push ((node){
    
    1, 0}); dis[1] = 0;
	while (!Q.empty())
	{
    
    
		u = Q.top();
		Q.pop();
		if (vis[u.id]) continue;
		vis[u.id] = 1;
		for (int i = h[u.id]; i; i = e[i].nxt)
		{
    
    
			v = e[i].to;
			if (!vis[v] && dis[u.id] + e[i].w < dis[v])
			{
    
    
				dis[v] = dis[u.id] + e[i].w;
				Q.push ((node){
    
    v, dis[v]});
			}
		}
	}
	for (int i = 2; i <= n; i++)
	{
    
    
		ans[i] = min (ans[i], dis[i + 2 * n]);
		ans[i] = min (ans[i], dis[i]);
	}
}

int main()
{
    
    
	int l;
	scanf ("%d%d", &n, &m);
	for (int i = 1; i <= m; i++)
	{
    
    
		scanf ("%d%d%lld", &U[i], &V[i], &W[i]);
		for (int j = 1; j <= 3; j++)
		{
    
    
			l = (j - 1) * n;
			add (l + U[i], l + V[i], W[i]);
			add (l + V[i], l + U[i], W[i]);
		}
		add (U[i], V[i] + n, 0);
		add (V[i], U[i] + n, 0);
		add (U[i] + n, V[i] + 2 * n, 2 * W[i]);
		add (V[i] + n, U[i] + 2 * n, 2 * W[i]);
	}
	memset (ans, 0x7f, sizeof (ans));
	dij ();
	cnt = 0;
	memset (h, 0, sizeof (h));
	for (int i = 1; i <= m; i++)
	{
    
    
		for (int j = 1; j <= 3; j++)
		{
    
    
			l = (j - 1) * n;
			add (l + U[i], l + V[i], W[i]);
			add (l + V[i], l + U[i], W[i]);
		}
		add (U[i], V[i] + n, 2 * W[i]);
		add (V[i], U[i] + n, 2 * W[i]);
		add (U[i] + n, V[i] + 2 * n, 0);
		add (V[i] + n, U[i] + 2 * n, 0);
	}
	dij ();
	for (int i = 2; i <= n; i++)
	  printf ("%lld ", ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43010386/article/details/121375156