飞行路线
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 }
原文地址:https://www.cnblogs.com/1013star/p/9576487.html