bzoj2763: [JLOI2011]飞行路线
Description
Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并且航线有一定的价格。Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多k种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少?
Input
数据的第一行有三个整数,n,m,k,分别表示城市数,航线数和免费乘坐次数。
第二行有两个整数,s,t,分别表示他们出行的起点城市编号和终点城市编号。(0<=s,t<n)
接下来有m行,每行三个整数,a,b,c,表示存在一种航线,能从城市a到达城市b,或从城市b到达城市a,价格为c。(0<=a,b<n,a与b不相等,0<=c<=1000)
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
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.
''建立分层图。
点 nt + i 表示已经改了 t 条边的边权, 从起点到 i 点的最短路长度。
那么对于任意一条边 (u, v, c)
在分层图建立无向边 (nt + u, nt + v, c)
与有向边 (nt + u, n(t + 1) + v, 0), (nt + v, n(t + 1) + u, 0)
直接跑最短路就好。''
——来自某课件
1 #include <stdio.h> 2 #include <queue> 3 #include <string.h> 4 #include <algorithm> 5 #define inf 2000000000 6 using namespace std; 7 typedef pair<long long , int > pii; 8 struct node 9 { 10 int u, v, w, next; 11 }a[3000010*2]; 12 int dis[200010]; 13 int rp, T, first[200010], n, m, tot, k; 14 int done[200010]; 15 void addedge(int st, int end, int val) 16 { 17 a[++tot].u = st;a[tot].v = end;a[tot].w = val; 18 a[tot].next =first[st];first[st] = tot; 19 } 20 int dij(int S) 21 { 22 priority_queue <pii, vector<pii>, greater<pii > > q; 23 memset(dis,0x7f,sizeof(dis));; 24 q.push(make_pair(0, S)); 25 dis[S] = 0; 26 while (!q.empty()) 27 { 28 int u = q.top().second;q.pop(); 29 if(done[u])continue; 30 done[u] = 1; 31 for (int e = first[u]; e != -1; e = a[e].next) 32 { 33 int v = a[e].v; 34 if (dis[u] + a[e].w < dis[v]) 35 { 36 dis[v] = dis[u] + a[e].w; 37 q.push(make_pair(dis[v], v)); 38 } 39 } 40 } 41 } 42 int main() 43 { 44 int ST, END, x, y, z; 45 scanf("%d %d %d", &n, &m, &k); 46 scanf("%d %d", &ST, &END); 47 ST++;END++; 48 memset(first, -1, sizeof(first)); 49 for (int i = 1; i <= m; i++) 50 { 51 scanf("%d %d %d", &x, &y, &z); 52 x++;y++; 53 for (int t = 0; t <= k; t++) 54 { 55 addedge(x+n*t, y+n*t, z); 56 addedge(y+n*t, x+n*t, z); 57 if(t == k)continue; 58 addedge(x+n*(t), n*(t+1)+y, 0); 59 addedge(y+n*(t), n*(t+1)+x, 0); 60 } 61 } 62 dij(ST); 63 int ans = inf; 64 for (int i = 0; i <= k; i++) 65 ans = min(dis[i*n+END], ans); 66 printf("%d\n", ans); 67 return 0; 68 }