1. 程式人生 > >洛谷P4568 [JLOI2011]飛行路線(分層圖最短路)

洛谷P4568 [JLOI2011]飛行路線(分層圖最短路)

題目描述

AliceAliceBobBob現在要乘飛機旅行,他們選擇了一家相對便宜的航空公司。該航空公司一共在nn個城市設有業務,設這些城市分別標記為00n1n-1,一共有mm種航線,每種航線連線兩個城市,並且航線有一定的價格。

AliceAliceBobBob現在要從一個城市沿著航線到達另一個城市,途中可以進行轉機。航空公司對他們這次旅行也推出優惠,他們可以免費在最多kk種航線上搭乘飛機。那麼AliceAliceBobBob這次出行最少花費多少?

輸入輸出格式

輸入格式: 資料的第一行有三個整數,n,m,kn,m,k

,分別表示城市數,航線數和免費乘坐次數。 第二行有兩個整數,s,ts,t,分別表示他們出行的起點城市編號和終點城市編號。 接下來有m行,每行三個整數,a,b,ca,b,c,表示存在一種航線,能從城市aa到達城市bb,或從城市bb到達城市aa,價格為cc

輸出格式:

只有一行,包含一個整數,為最少花費。

輸入樣例#1:

5 6 1
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100

輸出樣例#1:

8

關於分層圖最短路

(以下來自度娘) 分層圖最短路是指在可以進行分層圖的圖上解決最短路問題。

一般模型是:

在圖上,有k次機會可以直接通過一條邊(也就是免費),問起點與終點之間的最短路徑。

一般解決這種問題的時候,我們要將最短路的disdis 陣列開成兩維。 dis[i][j]dis[i][j] 表示我走到了ii號點,使用了jj次機會的最短路徑是多少。

如何更新?

disdis陣列可以由兩個方式更新,對應著兩種操作——在這個點我用不用一次機會。 我們設邊 E(u,v)E(u , v) 如果用這次機會 dis[v][j]=dis[u][j1]dis[v][j] = dis[u][j-1] 如果不用這次機會dis[v][j]=dis[u][j]+val(u,v)dis[v][j] = dis[u][j] + val(u,v)

這些操作我們完全可以在SPFA或Dijkstra更新最短路時實現。

還要注意一個坑點 這個題的編號是從00 開始的,如果不習慣的話輸入時要把編號加上11

code

#include<bits/stdc++.h>

using namespace std;

const int maxn = 10005, maxm = 100005;
struct node
{
	int f, t, v;
}e[maxm];
int n, m, tot, k, S, T, ans = 1e9;
int head[maxn], nxt[maxm], used[maxn] , dis[maxn][12];
#define ri register int
inline int read()
{
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
	return x * f;
}
inline void buildnode(int a, int b, int c)
{
	tot++;
	e[tot].f = a;
	e[tot].t = b;
	e[tot].v = c;
	nxt[tot] = head[a];
	head[a] = tot;
}
typedef pair<int, int>p;
struct cmp
{
	bool operator()(p a, p b)
	{
		return a.first > b.first;
	}
};
priority_queue<p, vector<p>, cmp>q;
inline void dijkstra(int s)
{
	for (ri i = 1; i <= n; i++)
		for (ri j = 0; j <= 10; j++) dis[i][j] = 1e9;
	dis[s][0] = 0;
	q.push(p(dis[s][0], s));
	while (!q.empty())
	{
		p x = q.top();
		q.pop();
		int flag = 0;
		for (ri i = head[x.second]; i; i = nxt[i])
		{
			int u = e[i].t;
			for(ri j = 0 ; j <= k ; j ++)
			if (dis[u][j] > dis[x.second][j] + e[i].v)
			{
				dis[u][j] = dis[x.second][j] + e[i].v;
				q.push(p(dis[u][j], u));
				flag = 1;
			}
			for (ri j = 1; j <= k; j++)
			{
				if (dis[u][j] > dis[x.second][j - 1])
					dis[u][j] = dis[x.second][j - 1], flag = 1;
			}
			if (flag == 1) q.push(p(dis[u][0], u));
		}
	}
}
int main()
{
	n = read(); m = read(); k = read();
	S = read(); T = read();
	S += 1; T += 1;
	for (ri i = 1; i <= m; i++)
	{
		int a, b, c;
		a = read(); b = read(); c = read();
		a += 1, b += 1;
		buildnode(a, b, c);
		buildnode(b, a, c);
	}
	dijkstra(S);
	for (ri i = 0; i <= k; i++) ans = min(ans, dis[T][i]);
	printf("%d", ans);
	//system("pause");
}

End