分层图+最短路算法 BZOJ 2763: [JLOI2011]飞行路线
Posted tech-chen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分层图+最短路算法 BZOJ 2763: [JLOI2011]飞行路线相关的知识,希望对你有一定的参考价值。
2763: [JLOI2011]飞行路线
Time Limit: 10 Sec Memory Limit: 128 MBDescription
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.
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define N 11000 6 #define M 51000 7 #define inf 0x3f3f3f3f 8 using namespace std; 9 struct KSD 10 { 11 int v,len,next; 12 }e[M<<1]; 13 int head[N],cnt; 14 struct Lux 15 { 16 int x,y; 17 Lux(int a,int b):x(a),y(b){} 18 Lux(){} 19 }; 20 void add(int u,int v,int len) 21 { 22 ++cnt; 23 e[cnt].v=v; 24 e[cnt].len=len; 25 e[cnt].next=head[u]; 26 head[u]=cnt; 27 } 28 int n,m,p,s,t; 29 int dist[11][N]; 30 bool in[11][N];/*spfa的dist,标记在每一层都要有*/ 31 queue<Lux>q; 32 int spfa() 33 { 34 int i,v; 35 memset(dist,0x3f,sizeof(dist)); 36 q.push(Lux(0,s));/*从第0层开始spfa*/ 37 dist[0][s]=0; 38 in[0][s]=1; 39 while(!q.empty()) 40 { 41 Lux U=q.front(); 42 q.pop(); 43 in[U.x][U.y]=0; 44 45 for(i=head[U.y];i;i=e[i].next) 46 { 47 v=e[i].v;/*先跑完这一层的最短路*/ 48 if(dist[U.x][v]>dist[U.x][U.y]+e[i].len) 49 { 50 dist[U.x][v]=dist[U.x][U.y]+e[i].len; 51 if(!in[U.x][v])q.push(Lux(U.x,v)),in[U.x][v]=1; 52 } 53 } 54 if(U.x<p)for(i=head[U.y];i;i=e[i].next) 55 {/*如果还可以向下一层转移的话,就把这个点出发的每一条边都设为免费下一层转移,因为要记录每个点dist到底用了几个免费的路线,所以用二维数组--分层思想*/ 56 v=e[i].v; 57 if(dist[U.x+1][v]>dist[U.x][U.y]) 58 { 59 dist[U.x+1][v]=dist[U.x][U.y]; 60 if(!in[U.x+1][v])q.push(Lux(U.x+1,v)),in[U.x+1][v]=1; 61 } 62 } 63 } 64 65 int ret=inf; 66 for(i=0;i<=p;i++)ret=min(ret,dist[i][t]);/*在每一层中都找到t的最小值(最多k条免费),为什么要在每一层都找,而不是只在最后一层寻找呢。假设有这么一种情况,由s--t的最少的路上的途径数目少于k条,那么在k之前的某一层上就有dis=0,但是如果必须使用k条路径的话,那么就会找的一条路途数多于k的路来满足这个条件,那么只用第k层的dis自然不是正确结果了。*/ 67 return ret; 68 } 69 70 int main() 71 { 72 // freopen("test.in","r",stdin); 73 int i,j,k; 74 int a,b,c; 75 scanf("%d%d%d%d%d",&n,&m,&p,&s,&t); 76 for(i=1;i<=m;i++) 77 { 78 scanf("%d%d%d",&a,&b,&c); 79 add(a,b,c);/*无向图建立双向边*/ 80 add(b,a,c); 81 } 82 printf("%d\n",spfa()); 83 return 0; 84 }
1 /*我的代码*/ 2 #define K 11 3 #include<iostream> 4 using namespace std; 5 #include<cstdio> 6 #include<queue> 7 #include<cstring> 8 #define N 10010 9 #define M 50010 10 struct QU{ 11 int ce,bh; 12 }; 13 struct Edge{ 14 int v,w,last; 15 }edge[M<<1]; 16 int head[N],dis[K][N],k,n,m,t=0,sta,en; 17 bool inque[K][N]; 18 inline int read() 19 { 20 int ff=1,ret=0; 21 char s=getchar(); 22 while(s<‘0‘||s>‘9‘) 23 { 24 if(s==‘-‘) ff=-1; 25 s=getchar(); 26 } 27 while(s>=‘0‘&&s<=‘9‘) 28 { 29 ret=ret*10+s-‘0‘; 30 s=getchar(); 31 } 32 return ret*ff; 33 } 34 void add_edge(int u,int v,int w) 35 { 36 ++t; 37 edge[t].v=v; 38 edge[t].w=w; 39 edge[t].last=head[u]; 40 head[u]=t; 41 } 42 void input() 43 { 44 n=read();m=read();k=read(); 45 sta=read();en=read(); 46 int a,b,c; 47 for(int i=1;i<=m;++i) 48 { 49 a=read();b=read();c=read(); 50 add_edge(a,b,c); 51 add_edge(b,a,c); 52 } 53 } 54 void SPFA() 55 { 56 memset(dis,100,sizeof(dis));/*注意赋值的最大值不要超界*/ 57 dis[0][sta]=0; 58 inque[0][sta]=true; 59 queue<QU>Q; 60 QU A; 61 A.ce=0; 62 A.bh=sta; 63 Q.push(A); 64 while(!Q.empty()) 65 { 66 QU NOw=Q.front(); 67 Q.pop(); 68 inque[NOw.ce][NOw.bh]=false; 69 for(int l=head[NOw.bh];l;l=edge[l].last) 70 { 71 if(dis[NOw.ce][edge[l].v]>edge[l].w+dis[NOw.ce][NOw.bh]) 72 { 73 dis[NOw.ce][edge[l].v]=edge[l].w+dis[NOw.ce][NOw.bh]; 74 if(!inque[NOw.ce][edge[l].v]) 75 { 76 inque[NOw.ce][edge[l].v]=true; 77 QU C; 78 C.bh=edge[l].v; 79 C.ce=NOw.ce; 80 Q.push(C); 81 } 82 } 83 } 84 if(NOw.ce==k) continue; 85 for(int l=head[NOw.bh];l;l=edge[l].last) 86 { 87 if(dis[NOw.ce+1][edge[l].v]>dis[NOw.ce][NOw.bh]) 88 { 89 dis[NOw.ce+1][edge[l].v]=dis[NOw.ce][NOw.bh]; 90 if(!inque[NOw.ce+1][edge[l].v]) 91 { 92 inque[NOw.ce+1][edge[l].v]=true; 93 QU C; 94 C.bh=edge[l].v; 95 C.ce=NOw.ce+1; 96 Q.push(C); 97 } 98 } 99 } 100 } 101 } 102 int main() 103 { 104 input(); 105 SPFA(); 106 int ans=(1<<31)-1; 107 for(int i=0;i<=k;++i) 108 ans=min(ans,dis[i][en]); 109 printf("%d\n",ans); 110 return 0; 111 } 112
以上是关于分层图+最短路算法 BZOJ 2763: [JLOI2011]飞行路线的主要内容,如果未能解决你的问题,请参考以下文章
Bzoj 2763: [JLOI2011]飞行路线 拆点,分层图,最短路,SPFA
Bzoj 2763: [JLOI2011]飞行路线 dijkstra,堆,最短路,分层图
BZOJ2763[JLOI2011]飞行路线 [分层图最短路]