zoj 3088 Easter Holidays(最长路+最短路+打印路径)

Scandinavians often make vacation during the Easter holidays in the largest ski resort Are. Are provides fantastic ski conditions, many ski lifts and slopes of various difficulty profiles. However, some lifts go faster than others, and some are so popular that a queue forms at the bottom.

Per is a beginner skier and he is afraid of lifts, even though he wants to ski as much as possible. Now he sees that he can take several different lifts and then many different slopes or some other lifts, and this freedom of choice is starting to be too puzzling...
He would like to make a ski journey that:

  • starts at the bottom of some lift and ends at that same spot
  • has only two phases: in the first phase, he takes one or more lifts up, in the second phase, he will ski all the way down back to where he started
  • is least scary, that is the ratio of the time spent on the slopes to the time spent on the lifts or waiting for the lifts is the largest possible.

Can you help Per find the least scary ski journey? A ski resort contains n places, m slopes, and k lifts (2 <= n <= 1000, 1 <= m <= 1000, 1 <= k <= 1000). The slopes and lifts always lead from some place to another place: the slopes lead from places with higher altitude to places with lower altitude and lifts vice versa (lifts cannot be taken downwards).

Input

The first line of the input contains the number of cases - the number of ski resorts to process. Each ski resort is described as follows: the first line contains three integers n, m, and k. The following m lines describe the slopes: each line contains three integers - top and bottom place of the slope (the places are numbered 1 to n), and the time it takes to go down the slope (max. 10000). The final k lines describe the lifts by three integers - the bottom and top place of the lift, and the time it takes to wait for the lift in the queue and be brought to its top station (max. 10000). You can assume that no two places are connected by more than one lift or by more than one slope.

Output

For each input case, the program should print two lines. The first line should contain a space-separated list of places in the order they will be visited - the first place should be the same as the last place. The second line should contain the ratio of the time spent in the slopes to the time spent on the lifts or wating for the lifts. The ratio should be rounded to the closest 1/1000th. If there are two possibilities, then the rounding is away from zero (e.g., 1.9812 and 1.9806 become 1.981, 3.1335 becomes 3.134, and 3.1345 becomes 3.135). If there are multiple journeys that prior to rounding are equally scary, print an arbitrary one.

Sample Input

1
5 4 3
1 3 12
2 3 6
3 4 9
5 4 9
4 5 12
5 1 12
4 2 18

Sample Output

4 5 1 3 4
0.875

题意:

给你一个滑雪场,有两种边(用雪橇上升可看做一种边,从雪坡滑下来可看做一种边),让你找到两点A、B,A->B为经过第一种边上去,所需时间t1,B->A为经过第二种边下来,所需时间t2,使得t2/t1最大。

 

思路:

用两种边分别建两个图,用n次SPFA找到一个图中的任意一点到任意一点的最短路,再用n次SPFA找到另一个图中的任意一点到任意一点的最长路,然后枚举取得t2/t1的最大值就够了。

这肯定是我写的最揪心的一次代码了,自己写着写着就乱了。。。要注意的是递归打印路径 以及邻接表的建立,在结构体数组里多加了一个变量next,具体用法见加边函数。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<queue>
  4 using namespace std;
  5 
  6 const int INF = 0x3f3f3f3f;
  7 const int maxn = 1100;
  8 struct node
  9 {
 10     int v,w;
 11     int next;
 12 }edge1[maxn],edge2[maxn];
 13 
 14 int n,m,k;
 15 int cnt;//边数;
 16 int p[maxn];//保存与起始顶点u有边相连的那些边对应的下标,相当于邻接表;
 17 int dis1[maxn][maxn],dis2[maxn][maxn];//dis[i][j]表示i为源点到j的最短路;
 18 int parent1[maxn][maxn],parent2[maxn][maxn];//parent[i][j]表示以i为源点,j的前驱
 19 int start,end;
 20 queue<int>que;
 21 
 22 void init()
 23 {
 24     memset(parent1,0,sizeof(parent1));
 25     memset(parent2,0,sizeof(parent2));
 26     memset(dis1,0,sizeof(dis1));
 27     memset(dis2,INF,sizeof(dis2));
 28 }
 29 void add_edge_1(int u, int v, int w)//建第一个图
 30 {
 31     cnt++;
 32     edge1[cnt].v = v;
 33     edge1[cnt].w = w;
 34     edge1[cnt].next = p[u];
 35     p[u] = cnt;
 36 }
 37 
 38 void add_edge_2(int u, int v, int w)//建第二个图
 39 {
 40     cnt++;
 41     edge2[cnt].v = v;
 42     edge2[cnt].w = w;
 43     edge2[cnt].next = p[u];
 44     p[u] = cnt;
 45 }
 46 void spfa1(int s)//spfa求最长路,dis1[][]初始化为最小
 47 {
 48     int inque[maxn];
 49     while(!que.empty())
 50         que.pop();
 51     memset(inque,0,sizeof(inque));
 52 
 53     parent1[s][s] = s;
 54     dis1[s][s] = 0;
 55     que.push(s);
 56     inque[s] = 1;
 57 
 58     while(!que.empty())
 59     {
 60         int u = que.front();
 61         que.pop();
 62         inque[u] = 0;
 63 
 64         for(int i = p[u];i;i = edge1[i].next)//注意p数组在这里的用法,找所有与u相连的边的下标
 65         {
 66             if(dis1[s][edge1[i].v] < dis1[s][u] + edge1[i].w)
 67             {
 68                 dis1[s][edge1[i].v] = dis1[s][u] + edge1[i].w;
 69                 parent1[s][edge1[i].v] = u;
 70                 if(!inque[edge1[i].v])
 71                 {
 72                     inque[edge1[i].v] = 1;
 73                     que.push(edge1[i].v);
 74                 }
 75             }
 76         }
 77     }
 78 }
 79 
 80 void spfa2(int s)//spfa求最短路,dis2[][]初始化为最大
 81 {
 82     int inque[maxn];
 83     while(!que.empty()) que.pop();
 84     memset(inque,0,sizeof(inque));
 85 
 86     parent2[s][s] = s;
 87     dis2[s][s] = 0;
 88     que.push(s);
 89     inque[s] = 1;
 90 
 91     while(!que.empty())
 92     {
 93         int u = que.front();
 94         que.pop();
 95         inque[u] = 0;
 96 
 97         for(int i = p[u]; i; i = edge2[i].next)
 98         {
 99             if(dis2[s][edge2[i].v] > dis2[s][u] + edge2[i].w)
100             {
101                 dis2[s][edge2[i].v] = dis2[s][u] + edge2[i].w;
102                 parent2[s][edge2[i].v] = u;
103                 if(!inque[edge2[i].v])
104                 {
105                     inque[edge2[i].v] = 1;
106                     que.push(edge2[i].v);
107                 }
108             }
109         }
110     }
111 }
112 void output2(int e, int s)//递归打印路径2(A->B)
113 {
114     if(e == s)
115         printf("%d",e);
116     else
117     {
118         output2(parent2[s][e],s);
119         printf(" %d",e);
120     }
121 }
122 void output1(int e,int s) //递归打印路径1(B->A)
123 {
124     if(e==s) return;
125     else
126     {
127         output1(parent1[s][e],s);
128         printf(" %d",e);
129     }
130 }
131 int main()
132 {
133     int test;
134     scanf("%d",&test);
135     while(test--)
136     {
137         scanf("%d %d %d",&n,&m,&k);
138         init();
139 
140         cnt = 0;
141         memset(p,0,sizeof(p));
142         for(int i = 0; i < m; i++)
143         {
144             int u,v,w;
145             scanf("%d %d %d",&u,&v,&w);
146             add_edge_1(u,v,w);
147         }
148         for(int i = 1; i <= n; i++)
149         {
150             spfa1(i);
151         }
152 
153         cnt = 0;
154         memset(p,0,sizeof(p));
155         for(int i = 0; i < k; i++)
156         {
157             int u,v,w;
158             scanf("%d %d %d",&u,&v,&w);
159             add_edge_2(u,v,w);
160         }
161         for(int i = 1; i <= n; i++)
162         {
163             spfa2(i);
164         }
165 
166         double ans = 0;
167         //枚举查找满足t2/t1最大的起始点A,B;
168         for(int i = 1; i <= n; i++)
169         {
170             for(int j = 1; j <= n; j++)
171             {
172                 if(i == j || dis2[i][j] == INF)
173                     continue;
174                 if(dis1[j][i]*1.0/dis2[i][j] > ans)
175                 {
176                     ans = dis1[j][i]*1.0/dis2[i][j];
177                     start = i;//A
178                     end = j;//B
179                 }
180             }
181         }
182         output2(end,start);
183         output1(start,end);
184         printf("\n");
185         printf("%.3lf\n",ans);
186     }
187     return 0;
188 }
View Code

 

 

转载于:https://www.cnblogs.com/LK1994/p/3414982.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值