飞行路线 HYSBZ - 2763 (分层图+Dijkstra && Spfa)
飞行路线
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
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.
题解:
对于k次免费花费,我们可以把图想像为有k+1层,从第0层到第k层,第0层表示没有用过这k次机会,第i层表示用过i次免费花费。对于分层,有两种方法。本题为双向边。
注意:最后要从所有层中的终点找答案,因为如果s-t只有少于k条路,而你选取免费k次在到达终点的答案就可能不对。
1.建图时分层:建k+1层图。然后有边的两个点,多建一条到下一层边权为0的单向边,如果走了这条边就表示用了一次免费机会
比如共有N个点,1~n表示第一层,(1+n)~(n+n)代表第二层,(1+2*n)~(n+2*n)代表第三层,(1+i*n)~(n+i*n)代表第i层。
注意该种方法:因为要建K+1层图,数组要开到n*(k+1),点的个数也为n*(k+1)。
Dijkstra解法:
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <queue>
5 #include <algorithm>
6 #define inf 0x3f3f3f3f
7 using namespace std;
8 int cnt,n,m,k;
9 const int maxn=1e6+10;
10 const int maxm=1e7;
11 int head[maxn],dis[maxn],vis[maxn];
12 struct edge{
13 int to;
14 int next;
15 int w;
16 }e[maxm];
17 void init()
18 {
19 memset(vis,0,sizeof(vis));
20 memset(head,-1,sizeof(head));
21 memset(dis,inf,sizeof(dis));
22 cnt=0;
23 }
24 void add(int x,int y,int w)
25 {
26 e[cnt].to=y;
27 e[cnt].w=w;
28 e[cnt].next=head[x];
29 head[x]=cnt++;
30 }
31 struct node{
32 int pos;
33 int cost;
34 node(){}
35 node(int pos,int cost):pos(pos),cost(cost){}
36 friend bool operator < (node a,node b)
37 {
38 return a.cost>b.cost;
39 }
40 };
41 void dijkstra(int st)
42 {
43 priority_queue<node>q;
44 dis[st]=0;
45 q.push(node(st,0));
46 while(!q.empty())
47 {
48 node now=q.top();
49 q.pop();
50 if(vis[now.pos])
51 continue;
52 vis[now.pos]=1;
53 for(int i=head[now.pos];i!=-1;i=e[i].next)
54 {
55 int u=e[i].to;
56 if(dis[u]>dis[now.pos]+e[i].w)
57 {
58 dis[u]=dis[now.pos]+e[i].w;
59 q.push(node(u,dis[u]));
60 }
61 }
62 }
63 }
64 int main()
65 {
66 cin>>n>>m>>k;
67 int st,ed;
68 cin>>st>>ed;
69 int a,b,c;
70 init();
71 for(int i=0;i<m;i++)
72 {
73 scanf("%d%d%d",&a,&b,&c);
74 for(int j=0;j<=k;j++)
75 {
76 add(a+j*n,b+j*n,c);
77 add(b+j*n,a+j*n,c);
78 if(j!=k)
79 {
80 add(a+j*n,b+(j+1)*n,0);
81 add(b+j*n,a+(j+1)*n,0);
82 }
83 }
84 }
85 dijkstra(st);
86 int ans=214748364;
87 for(int i=0;i<=k;i++)
88 {
89 ans=min(ans,dis[i*n+ed]);
90 }
91 printf("%d\n",ans);
92 return 0;
93 }
spfa解法:
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <queue>
5 #include <algorithm>
6 #define inf 0x3f3f3f3f
7 using namespace std;
8 int cnt,n,m,k;
9 const int maxn=3e6+10;
10 const int maxm=1e7;
11 int head[maxn],dis[maxn],vis[maxn];
12 struct edge{
13 int to;
14 int next;
15 int w;
16 }e[maxn<<1];
17 void init()
18 {
19 memset(vis,0,sizeof(vis));
20 memset(head,-1,sizeof(head));
21 memset(dis,inf,sizeof(dis));
22 cnt=0;
23 }
24 void add(int x,int y,int w)
25 {
26 e[cnt].to=y;
27 e[cnt].w=w;
28 e[cnt].next=head[x];
29 head[x]=cnt++;
30 }
31 struct node{
32 int pos;
33 int cost;
34 node(){}
35 node(int pos,int cost):pos(pos),cost(cost){}
36 friend bool operator < (node a,node b)
37 {
38 return a.cost>b.cost;
39 }
40 };
41 void dijkstra(int st)
42 {
43 priority_queue<node>q;
44 dis[st]=0;
45 q.push(node(st,0));
46 vis[st]=1;
47 while(!q.empty())
48 {
49 node now=q.top();
50 q.pop();
51 vis[now.pos]=0;
52 for(int i=head[now.pos];i!=-1;i=e[i].next)
53 {
54 int u=e[i].to;
55 if(dis[u]>dis[now.pos]+e[i].w)
56 {
57 dis[u]=dis[now.pos]+e[i].w;
58 if(!vis[u])
59 vis[u]=1;
60 q.push(node(u,dis[u]));
61 }
62 }
63 }
64 }
65 int main()
66 {
67 int st,ed;
68 scanf("%d%d%d",&n,&m,&k);
69 scanf("%d%d",&st,&ed);
70 int a,b,c;
71 init();
72 for(int i=0;i<m;i++)
73 {
74 scanf("%d%d%d",&a,&b,&c);
75 for(int j=0;j<=k;j++)
76 {
77 add(a+j*n,b+j*n,c);
78 add(b+j*n,a+j*n,c);
79 if(j!=k)
80 {
81 add(a+j*n,b+(j+1)*n,0);
82 add(b+j*n,a+(j+1)*n,0);
83 }
84 }
85 }
86 dijkstra(st);
87 int ans=214748364;
88 for(int i=0;i<=k;i++)
89 {
90 ans=min(ans,dis[i*n+ed]);
91 }
92 printf("%d\n",ans);
93 return 0;
94 }