D - 小Y上学记——要迟到了!
D - 小Y上学记——要迟到了!
Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Problem Description
“你是我心中最美的云彩....",这不是大妈的广场舞,而是小Y的闹钟,然而小Y由于昨晚玩得太疯,导致今天居然没被这铃声闹醒!
当小Y睡眼惺忪地醒来后,发现距离第一节上课还有不到5分钟了!
小Y心想,跑过去教室肯定来不及了,只好发动一下超能力。
小Y的超能力是可以瞬间通过一条路,也就是说从一头瞬间移动到另一头,然而由于某种原因,小Y最多只能发动K次,不然就会被大家发现,就会被上交给国家。
那么小Y想问你最快要多长时间到达教室?
Input
多组数据,每组数据首先是三个整数N,M,K,表示校园道路的节点数,校园道路数,还有小Y能发动超能力的最大次数。
(2<=N<=1000,N-1<=M<=10000,0<=K<=10)
接下来是M行,每行是三个数字u,v,w,表示在节点u和节点v中有一条需要小Y跑w分钟的路,道路都是没有方向限制的。
(1<=u,v<=N,0<w<=1000)
可能有自环以及重边
其中小Y宿舍在1号节点,教室在n号节点。
保证从宿舍到教室至少存在一条路。
Output
对于每组数据,输出一个整数,表示小Y在超能力的帮助下最少要多少时间到达教室。
Sample Input
4 4 0 1 2 2 2 4 3 1 3 1 3 4 4 4 4 1 1 2 2 2 4 3 1 3 1 3 4 4
Sample Output
5 1
Hint
对于第一组数据,由于小Y不能使用超能力,无论是1-2-4还是1-3-4,都需要花费小Y5分钟的时间
对于第二组数据,由于小Y可以用一次超能力,因此可以选择1-3-4这条道路,其中3-4这条道路使用超能力通过。只需要1分钟。
解法:
要使得所用时间最少,当然是尽可能的使用全部次数的超能力,把平面二维的图,弄成立体三维的,一共有K+1层,表示有K次超能力。则把每两层之间的连接的边权看作为0,然后用广度搜索的方法以及SPFA的思想,去求这个三维图的最短路径,起始点为Dis[0][1],终点为Dis[K][N]。注意要判断重边,环,以及数组,邻接表要开足够大、
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h> 2 #include<string.h> 3 #define INF 99999999 4 #define MAX 1016 5 using namespace std; 6 int Dis[15][MAX];/*Dis[i][j]记录到达第i层的点j的最短路*/ 7 int Sign[100810];/*队列*/ 8 int D_ID[100810];/*记录队列元素所对的层数*/ 9 int First[MAX]; /*邻接表头*/ 10 struct edge{int TO,Next,Vlaue;}ID[MAX*20];/*邻接表*/ 11 int SIGN;/*边编号,从1开始*/ 12 13 void Add_E(int x,int y,int z) /*添加边*/ 14 { 15 ID[SIGN].TO=y; 16 ID[SIGN].Vlaue=z; 17 ID[SIGN].Next=First[x]; 18 First[x]=SIGN++; 19 } 20 void Cread(int N,int K)/*初始化*/ 21 { 22 int i,j; 23 for(i=0;i<=K;i++) 24 { 25 for(j=1;j<=N;j++) 26 {First[j]=0;Dis[i][j]=INF;} 27 } 28 } 29 void Jude(int x,int y,int c)/*判断重边,添加点*/ 30 { 31 int i; 32 int TMD=1; 33 for(i=First[x];i!=0;i=ID[i].Next) 34 { 35 if(ID[i].TO==y) 36 { 37 TMD=0; 38 if(ID[i].Vlaue>c) 39 {ID[i].Vlaue=c;TMD=2;break;} 40 } 41 } 42 if(TMD==2) 43 { 44 for(i=First[y];i!=0;i=ID[i].Next) 45 { 46 if(ID[i].TO==x) 47 { 48 if(ID[i].Vlaue>c) 49 {ID[i].Vlaue=c;break;} 50 } 51 } 52 return ; 53 } 54 if(TMD==1) 55 { 56 Add_E(x,y,c);/*无线图,所以需要左右两边*/ 57 Add_E(y,x,c);/*无线图,所以需要左右两边*/ 58 } 59 return ; 60 } 61 void SPFA(int s,int m,int K) 62 { 63 int i,j,k,Start=0,End=1,D=0; 64 int Visit[15][MAX]; 65 Sign[Start] = s; 66 D_ID[Start]=0; 67 Dis[D][s] = 0; 68 while(Start<End) 69 { 70 D=D_ID[Start];/*获取队头元素的层数*/ 71 k=Sign[Start++];/*获取队头元素(点)*/ 72 Visit[D][k]=0; 73 for(i=First[k];i!=0;i=ID[i].Next)/*更新第D层的最短路*/ 74 { /*更新第D层的最短路*/ 75 if(ID[i].Vlaue>0&&Dis[D][ID[i].TO]>ID[i].Vlaue+Dis[D][k]) 76 { 77 Dis[D][ID[i].TO]=Dis[D][k]+ID[i].Vlaue; 78 if(!Visit[D][ID[i].TO]) 79 { 80 D_ID[End]=D;/*记录入队元素的层数*/ 81 Sign[End++]=ID[i].TO; 82 Visit[D][ID[i].TO]=1; 83 } 84 } 85 } 86 for(i=First[k],D=D+1;i!=0&&D<=K;i=ID[i].Next) 87 { /*更新第D+1层的最短路*/ 88 if(ID[i].Vlaue>0&&Dis[D][ID[i].TO]>Dis[D-1][k]) 89 { 90 Dis[D][ID[i].TO]=Dis[D-1][k]; 91 if(!Visit[D][ID[i].TO]) 92 { 93 D_ID[End]=D; 94 Sign[End++]=ID[i].TO; 95 Visit[D][ID[i].TO]=1; 96 } 97 } 98 } 99 } 100 return ; 101 } 102 int main() 103 { 104 int i,j,T,N,a,b,c,K; 105 while(scanf("%d%d%d",&N,&T,&K)!=EOF) 106 { 107 Cread(N,K);SIGN=1; 108 for(i=0;i<T;i++) 109 { 110 scanf("%d%d%d",&a,&b,&c); 111 Jude(a,b,c); 112 } 113 SPFA(1,N,K); 114 printf("%d\n",Dis[K][N]); 115 } 116 return 0; 117 }
转载请备注:
**************************************
* 作者: Wurq
* 博客: https://www.cnblogs.com/Wurq/
* Gitee: https://gitee.com/wurq
**************************************
**************************************
* 作者: Wurq
* 博客: https://www.cnblogs.com/Wurq/
* Gitee: https://gitee.com/wurq
**************************************