(中等) 最短路 HOJ 2132 Easter holidays

Easter holidays

My Tags  (Edit)
Source : Nordic Collegiate Programming Contest 2004
Time limit : 3 secMemory limit : 32 M

Submitted : 63, Accepted : 11

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 Ouput

4 5 1 3 4
0.875

题意:主人公从一个节点出发,可以往上爬到某一个高度,然后从那里回来这个节点,问怎么走能使往下走的时间与往上走的时间比例最大。

思路:
显然对于一个“底端”和一个“顶端”比例最大的时候是往上跑的时间最小,往下跑的时间最大。
那么思路就来了,求出每一对节点之间的最小往上跑路径和最大往下跑路径。问题就转化为最长路和最短路的问题。

代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<map>
#include<queue>
#include<string.h>
#include<vector>
#include<string>
using namespace std;
#define mp make_pair

const int maxn = 1000+10;
const double eps = 1e-8;
const int inf = 1e9;
vector<int> G_down[maxn];
vector<int> G_up[maxn];
int d_up[maxn][maxn];
int d_down[maxn][maxn];
int pre_up[maxn][maxn];
int pre_down[maxn][maxn];
int w[maxn][maxn];
bool inq[maxn];
int d[maxn];
int path[2*maxn];

int n , m , k;
void init()
{
for (int i = 1 ; i <= n ; ++i) G_down[i].clear() , G_up[i].clear();
memset(pre_down,-1,sizeof(pre_down));
memset(pre_up,-1,sizeof(pre_up));
for (int i = 1 ; i <= n ; ++i) 
for (int j = 1 ; j <= n ; ++j) d_up[i][j] = inf;
memset(d_down,0,sizeof(d_down));
scanf("%d%d%d",&n,&m,&k);
int x , y;
while (m--)
{
scanf("%d%d",&x,&y);
G_down[x].push_back(y);
scanf("%d",&w[x][y]);
}
while (k--)
{
scanf("%d%d",&x,&y);
scanf("%d",&w[x][y]);
G_up[x].push_back(y);
}
}

typedef pair<int,int> node;
void Spfa_down(int s)
{
memset(inq,0,sizeof(inq));
memset(d,-1,sizeof(d));
queue<int> q;
q.push(s);
d[s] = 0;
inq[s] = true;
while (q.size())
{
int x = q.front(); q.pop();
inq[x] = false;
for (int i = 0 ; i < G_down[x].size() ; ++i)
{
int y = G_down[x][i];
if (d[y] < d[x]+w[x][y])
{
d[y] = d[x]+w[x][y];
pre_down[s][y] = x;
if (!inq[y])
{
inq[y] = true;
q.push(y);
}
}
}
}
for (int i = 1 ; i <= n ; ++i) d_down[s][i] = d[i];
}

void Spfa_up(int s)
{
memset(inq,0,sizeof(inq));
for (int i = 1 ; i <= n ; ++i) d[i] = inf;
queue<int> q;
q.push(s);
d[s] = 0;
while (q.size())
{
int x = q.front(); q.pop();
inq[x] = false;
for (int i = 0 ; i < G_up[x].size() ; ++i)
{
int y = G_up[x][i];
if (d[y] > d[x]+w[x][y])
{
d[y] = d[x]+w[x][y];
pre_up[s][y] = x;
if (!inq[y])
{
inq[y] = true;
q.push(y);
}
}
}
}
for (int i = 1 ; i <= n ; ++i) d_up[s][i] = d[i];
}

void solve()
{
for (int i = 1 ; i <= n ; ++i)
{
Spfa_up(i);
Spfa_down(i);
}
int s , t;
double ans = 0;
for (int i = 1 ; i <= n ; ++i)
{
for (int j = 1 ; j <= n ; ++j) if (i!=j && d_down[j][i]!=-1 && d_up[i][j]!=inf)
{
double tmp = (double)d_down[j][i]/d_up[i][j];
if (ans < tmp)
{
ans = tmp;
s = i , t = j;
}
}
}
int top = 0;
int x = pre_up[s][t];
path[top++] = t;
while (x!=-1)
{
path[top++] = x;
x = pre_up[s][x];
}
printf("%d",path[--top]);
while (top > 0 )  printf(" %d",path[--top]);
x = pre_down[t][s];
path[top++] =s;
while (x!=-1)
{
path[top++] = x;
x = pre_down[t][x];
}
--top;
while (top > 0) printf(" %d",path[--top]);
printf("\n%.3lf\n",ans+eps);
}

int main()
{
//double a = 1.9805;
//printf("%.3lf",a+eps);
int T;
cin>>T;
while (T--)
{
init();
solve();
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值