[JLOI2011]飞行路线【分层图最短路】【dijkstra】

>Link

luogu P4568


>Description

给出一张 n n n 个点, m m m 条边的无向图。选择其中的一条路,可以最多减去其中 k k k 条路径的权值
S S S T T T 的最短路

n ≤ 1 0 4 , m ≤ 5 ∗ 1 0 4 , k ≤ 10 n\le 10^4,m\le5*10^4,k\le10 n104,m5104,k10


>解题思路

我们把点复制成 k + 1 k+1 k+1 层,其中跨去另一层的次数为 k k k,可以在这之间搞减去的路径的权值
把相邻两层之间的边权值赋为 0,每层之间正常建边,这样从一层走到另一层就相当于把这条路径的权值减去了
最终答案就是第 S S S 层的 1 1 1 到第 k k k 层的 T T T 的最短路

SPFA会被卡,这里用到dij+堆优化 SPFA已经死了 (虽然但是我之前一直在用SPFA)


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 800010
using namespace std;

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

void add (int u, int v, int w)
{
    
    
	e[++cnt] = (edge){
    
    v, h[u], w};
	h[u] = cnt;
}

int main()
{
    
    
//	printf ("%.3lf", (double) sizeof (vis) / 1024 / 1024);
	scanf ("%d%d%d%d%d", &n, &m, &k, &S, &T);
	S++, T++;
	int u, v, w, l;
	for (int i = 1; i <= m; i++)
	{
    
    
		scanf ("%d%d%d", &u, &v, &w);
		u++, v++;
		for (int j = 1; j <= k + 1; j++)
		{
    
    
			l = (j - 1) * n;
			add (l + u, l + v, w);
			add (l + v, l + u, w);
			if (j > 1)
			{
    
    
				add (l - n + u, l + v, 0);
				add (l - n + v, l + u, 0);
			}
		}
	}
	memset (dis, 0x7f, sizeof (dis));
	ans = dis[0];
	Q.push ((node){
    
    S, 0}); dis[S] = 0;
	while (!Q.empty())
	{
    
    
		node 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 = 1; i <= k + 1; i++)
	  ans = min (ans, dis[(i - 1) * n + T]);
	printf ("%d", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43010386/article/details/121375015
今日推荐