Repairing a Road

6 篇文章 0 订阅
3 篇文章 0 订阅

2010省赛题:Repairing a Road

http://acm.hnust.cn/JudgeOnline/problem.php?id=1504


时间限制: 1 Sec 内存限制: 128 MB
提交: 47 解决: 20
[提交][状态][讨论版]
题目描述
题目描述

You live in a small town with R bidirectional roads connecting C crossings and you want to go from crossing 1 to crossing C as soon as possible. You can visit other crossings before arriving at crossing C, but it’s not mandatory.

You have exactly one chance to ask your friend to repair exactly one existing road, from the time you leave crossing 1. If he repairs the i-th road for t units of time, the crossing time after that would be viai-t. It’s not difficult to see that it takes vi units of time to cross that road if your friend doesn’t repair it.

You cannot start to cross the road when your friend is repairing it.

输入

There will be at most 25 test cases. Each test case begins with two integers C and R (2<=C<=100, 1<=R<=500). Each of the next R lines contains two integers xi, yi (1<=xi, yi<=C) and two positive floating-point numbers vi and ai (1<=vi<=20,1<=ai<=5), indicating that there is a bidirectional road connecting crossing xi and yi, with parameters vi and ai (see above). Each pair of crossings can be connected by at most one road. The input is terminated by a test case with C=R=0, you should not process it.

输出

For each test case, print the smallest time it takes to reach crossing C from crossing 1, rounded to 3 digits after decimal point. It’s always possible to reach crossing C from crossing 1.

样例输入

3 2

1 2 1.5 1.8

2 3 2.0 1.5

2 1

1 2 2.0 1.80

0

样例输出

2.589

1.976

题意:给C个顶点(从1开始编号), R条边, 的无向图. 其中每条边上有起点, 终点, 时间权值vi, 和另一参数ai;对一条边使用ai,则可以节省通过该边的时间, 具体见题目. 问,从1->C的所有路径中, 只对某一条边使用ai参数, 则所需最少时间是? 从准备离开1时开始计时(不一定离开了,可以选择等待,见样例2,印象中是等待了0.275s), 其中函数所指的t是踏上某条边前的所经过的时间.

思路: 先用floyd算法吧每两点间的最短距离算出, 然后暴力枚举每条可以用于节省时间的边; 复杂度就是floyd的时间复杂度, 数据25组,O(1e7); 可行!

#include <iostream>
#include <cmath>
#include <cstdio>
#define LL long long
#include <cstring>
#define INF 100000000000
#include <queue>
#define eps (1e-6)

using namespace std;
typedef struct edge
{
    LL from,to;
    double v,a;
}edge;
double cost[110][110];//floyd,cost 用于存储两点间的最短路
queue<edge> que;//用于暴力枚举每一条两点间的最短边
LL N,R;//N,R分别是顶点和边的数目
double sum;
void init()
{
    while (!que.empty())
        que.pop();
    for (int i=1;i<=N;i++)
    {
        for(int j=1;j<=N;j++)
        {
            if (i==j)
                cost[i][j]=0;
            else
                cost[i][j]=INF;
        }
    }
}
void input()
{
    edge e;
    LL temp;
    for (int i=1;i<=R;i++)
    {
        scanf("%I64d %I64d %lf %lf",&e.from,&e.to,&e.v,&e.a);
        if (e.v<cost[e.from][e.to])
            cost[e.from][e.to]=e.v;//无向图,双向边
        if (e.v<cost[e.to][e.from])
            cost[e.to][e.from]=e.v;//不考虑修路效果情况下,最短路由e.v构成
        que.push(e);
        temp=e.from;
        e.from=e.to;
        e.to=temp;
        que.push(e);
    }
}
void floyd()
{
    for (int k=1;k<=N;k++)
    {
        for (int i=1;i<=N;i++)
        {
            for (int j=1;j<=N;j++)
            {
                cost[i][j]=min(cost[i][k]+cost[k][j],cost[i][j]);
            }
        }
    }
}
void solve()
{
    edge e;
    double limit;//记录对于每条边递增函数的起点
    while (!que.empty())
    {
        e=que.front();que.pop();
        if (abs(e.a-1)>eps)//防止出现除零错误
            limit=log(e.v*log(e.a))/log(e.a);  
        else   //数学计算:y = t + v*a^(-t); => y'=1+(-v*a^(-t)ln(a))=0; => a^t=v*ln(a); => t=log(a,v*ln(a))=log(e,v*ln(a))/log(e,a);                                  
            limit=0;
        if (cost[1][e.from]<limit)
        { //sum = min( min(1->e.from) + f(e.from,e.to) + min(e.to->N) )  e:所有可能的边,考虑方向,所以e入队时做了处理                         
            if (limit+e.v*pow(e.a,-limit)+cost[e.to][N] < sum)
                sum=limit+e.v*pow(e.a,-limit)+cost[e.to][N];
        }
        else
        {
            limit=cost[1][e.from];
            if (limit+e.v*pow(e.a,-limit)+cost[e.to][N] < sum)
                sum=limit+e.v*pow(e.a,-limit)+cost[e.to][N];
        }
    }
}
int main()
{
    while (scanf("%I64d%I64d",&N,&R)==2&&(R||N))
    {
        init();
        input();
        floyd();
        sum=cost[1][N];
        solve();
        printf("%.3lf\n",sum);
    }
    return 0;
}

博客仅供参考学习,请勿抄袭!转载请注明出处!!!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值