Description
Alice和Bob現在要乘飛機旅行,他們選擇了一家相對便宜的航空公司。該航空公司一共在n個城市設有業務,設這些城市分別標記爲0到n-1,一共有m種航線,每種航線連接兩個城市,並且航線有一定的價格。Alice和Bob現在要從一個城市沿着航線到達另一個城市,途中可以進行轉機。航空公司對他們這次旅行也推出優惠,他們可以免費在最多k種航線上搭乘飛機。那麼Alice和Bob這次出行最少花費多少?
Input
數據的第一行有三個整數,n,m,k,分別表示城市數,航線數和免費乘坐次數。
第二行有兩個整數,s,t,分別表示他們出行的起點城市編號和終點城市編號。(0<=s,t
Output
只有一行,包含一個整數,爲最少花費。
Sample Input
5 6 1
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100
Sample Output
8
HINT
對於30%的數據,2<=n<=50,1<=m<=300,k=0;
對於50%的數據,2<=n<=600,1<=m<=6000,0<=k<=1;
對於100%的數據,2<=n<=10000,1<=m<=50000,0<=k<=10.
思路
分層圖最短路的模板題,此題洛谷上卡SPFA
,所以用堆優化的dijkstra
來做.
題意就是,給出你一張無向圖,你有k
次機會使得某一條邊的花費爲0
,求最小花費.
我們需要利用類似動態規劃的思想來進行轉移。
我們定義:
- :從起點
st
到i
點,使用了j
次優惠機會所使用的最小花費. - :從起點
st
到i
點,使用了j
次優惠機會這個狀態有沒有被標記
我們需要對普通的迪傑斯特拉轉移的時候進行一些改變:
不使用免費機會的時候:
如果 到點u的花費dis[u][k]+從u到v的邊權w<到v的邊權dis[v][k] 正常轉移更新:dis[v][k]=dis[u][k]+w 加入堆q.push(node(v,k,dis[v][k]))
使用免費機會的時候:
如果 到點u的時候使用了k次機會的花費dis[u][k]<到v點的時候使用了k+1次機會的邊權dis[v][k+1] 這條邊免費更新dis[v][k+1]=dis[u][k] 加入堆q.push(node(v,k+1,dis[v+1][k]))
剩下的就是迪傑斯特拉的堆優化模板了。
代碼
#include <bits/stdc++.h>
using namespace std;
#define mem(a, b) memset(a, b, sizeof(a))
const int N = 1e5 + 10;
const int inf = 0x3f3f3f3f;
int n, m, k;
int first[N], tot;
struct edge
{
int v, w, next;
} e[N * 2];
void add_edge(int u, int v, int w)
{
e[tot].v = v, e[tot].w = w;
e[tot].next = first[u];
first[u] = tot++;
}
struct node
{
int id, now, k;
node() {}
node(int _id, int _k, int _now)
{
id = _id, now = _now, k = _k;
}
bool friend operator<(node a, node b)
{
return a.now > b.now;
}
};
/*
dis[i][j]:表示從st到i點用了j次免費機會的最小花費
vis[i][j]:表示從st到i點用了j次免費機會有沒有被標記過
*/
int dis[N][12], vis[N][12];
void dijkstra(int st)
{
for (int i = 1; i <= n; i++)
{
for (int j = 0; j <= k; j++)
{
dis[i][j] = inf;
vis[i][j] = 0;
}
}
dis[st][0] = 0;
priority_queue<node> q;
q.push(node(st, 0, 0));
while (!q.empty())
{
node u = q.top();
q.pop();
if (!vis[u.id][u.k])
{
vis[u.id][u.k] = 1;
for (int i = first[u.id]; ~i; i = e[i].next)
{
int v = e[i].v, w = e[i].w;
if (!vis[v][u.k] && dis[u.id][u.k] + w < dis[v][u.k])
{
dis[v][u.k] = dis[u.id][u.k] + w;
q.push(node(v, u.k, dis[v][u.k]));
}
if (u.k < k && !vis[v][u.k + 1] && dis[u.id][u.k] < dis[v][u.k + 1])
{
dis[v][u.k + 1] = dis[u.id][u.k];
q.push(node(v, u.k + 1, dis[v][u.k + 1]));
}
}
}
}
}
void init()
{
mem(first, -1);
tot = 0;
}
int main()
{
//freopen("in.txt", "r", stdin);
int u, v, w, st, ed;
scanf("%d%d%d%d%d", &n, &m, &k, &st, &ed);
st++, ed++;
init();
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d", &u, &v, &w);
u++, v++;
add_edge(u, v, w);
add_edge(v, u, w);
}
dijkstra(st);
int ans = inf;
for (int i = 0; i <= k; i++)
ans = min(ans, dis[ed][i]);
printf("%d\n", ans);
return 0;
}