luogu P4568 [JLOI2011] 飞行路线
Description–
一共有 n n n 个城市,分别标记为 0 0 0 到 n − 1 n-1 n−1,一共有 m m m 种航线,每种航线连接两个城市,并且航线有一定的价格,可以免费在最多 k k k 种航线上搭乘飞机。
花费多少?
Input–
第一行三个整数 n , m , k n,m,k n,m,k,分别表示城市数,航线数,免费乘坐次数
接下来一行两个整数 s , t s,t s,t,分别表示起点城市和终点城市
接下来 m m m 行,每行三个整数 a , b , c a,b,c a,b,c,表示存在一种航线,能从城市 a a a 到达城市 b b b,或从城市 b b b 到达城市 a a a,价格为 c c c
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
说明–
解题思路–
模板题
建图的时候建成
k
k
k 层,每下一层无需代价,再跑一遍最短路(要用dij,spfa会被卡
答案在第
k
k
k 层的终点
代码–
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
int n, m, k, s, t, a, b, c, cnt;
int ls[2100000], dis[2100000];
bool pd[2100000];
struct hll
{
int x, y, next;
}f[5100000];
struct node
{
int x, y;
friend bool operator < (node xx, node yy)
{
return xx.y > yy.y;
}
};
priority_queue<node> q;
void add(int xx, int yy, int zz)
{
f[++cnt] = (hll){yy, zz, ls[xx]}, ls[xx] = cnt;
}
void dij()
{
memset(dis, 0x7f, sizeof(dis));
dis[s] = 0, q.push((node){s, 0});
while (!q.empty())
{
node u = q.top();
q.pop();
if (pd[u.x]) continue;
pd[u.x] = 1;
for (int i = ls[u.x]; i; i = f[i].next)
if (!pd[f[i].x] && dis[u.x] + f[i].y < dis[f[i].x])
{
dis[f[i].x] = dis[u.x] + f[i].y;
q.push((node){f[i].x, dis[f[i].x]});
}
}
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
scanf("%d%d", &s, &t);
for (int i = 1; i <= m; ++i)
{
scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, c);
for (int j = 1; j <= k; ++j)
{
add(a + (j - 1) * n, b + j * n, 0); //下一层无需代价
add(b + (j - 1) * n, a + j * n, 0);
add(a + j * n, b + j * n, c);
add(b + j * n, a + j * n, c);
}
}
for (int i = 1; i <= k; ++i) //把每一层的终点连起来
add(t + (i - 1) * n, t + i * n, 0);
dij();
printf("%d", dis[t + k * n]);
return 0;
}