湖南省第6届程序大赛 Repairing a Road

Problem G

Repairing a Road

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.

Input

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.

Output

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.

Sample Input

Output for the Sample Input


3 2

1 2 1.5 1.8

2 3 2.0 1.5

2 1

1 2 2.0 1.8

0 0

2.589

1.976

题意:给C个顶点(从1开始编号), R条边, 的无向图. 其中每条边上有起点, 终点, 时间权值vi, 和另一参数ai。如果这道路总共修了t时间,那么这条路的花费就会变成 vi * ai ^ (-t)。我们要从1走到C,求最小花费(花费就是时间)。

思路: 先用floyd把每两点间的最短距离算出, 判断出这俩点是否相通,如果相通的话,暴力枚举每条可以用于节省时间的边。

  1 #include <iostream>
  2 #include <cmath>
  3 #include <cstdio>
  4 #define LL long long
  5 #include <cstring>
  6 #define INF 100000000000
  7 #include <queue>
  8 #define eps (1e-6)
  9
 10 using namespace std;
 11 typedef struct edge
 12 {
 13     LL from,to;
 14     double v,a;
 15 }edge;
 16 double cost[110][110];//floyd,cost 用于存储两点间的最短路
 17 queue<edge> que;//用于暴力枚举每一条两点间的最短边
 18 LL N,R;//N,R分别是顶点和边的数目
 19 double sum;
 20 void init()
 21 {
 22     while (!que.empty())
 23         que.pop();
 24     for (int i=1;i<=N;i++)
 25     {
 26         for(int j=1;j<=N;j++)
 27         {
 28             if (i==j)
 29                 cost[i][j]=0;
 30             else
 31                 cost[i][j]=INF;
 32         }
 33     }
 34 }
 35 void input()
 36 {
 37     edge e;
 38     LL temp;
 39     for (int i=1;i<=R;i++)
 40     {
 41         scanf("%I64d %I64d %lf %lf",&e.from,&e.to,&e.v,&e.a);
 42         if (e.v<cost[e.from][e.to])
 43             cost[e.from][e.to]=e.v;//无向图,双向边
 44         if (e.v<cost[e.to][e.from])
 45             cost[e.to][e.from]=e.v;//不考虑修路效果情况下,最短路由e.v构成
 46         que.push(e);
 47         temp=e.from;
 48         e.from=e.to;
 49         e.to=temp;
 50         que.push(e);
 51     }
 52 }
 53 void floyd()
 54 {
 55     for (int k=1;k<=N;k++)
 56     {
 57         for (int i=1;i<=N;i++)
 58         {
 59             for (int j=1;j<=N;j++)
 60             {
 61                 cost[i][j]=min(cost[i][k]+cost[k][j],cost[i][j]);
 62             }
 63         }
 64     }
 65 }
 66 void solve()
 67 {
 68     edge e;
 69     double limit;//记录对于每条边递增函数的起点
 70     while (!que.empty())
 71     {
 72         e=que.front();que.pop();
 73         if (abs(e.a-1)>eps)//防止出现除零错误
 74             limit=log(e.v*log(e.a))/log(e.a);
 75         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);
 76             limit=0;
 77         if (cost[1][e.from]<limit)
 78         { //sum = min( min(1->e.from) + f(e.from,e.to) + min(e.to->N) )  e:所有可能的边,考虑方向,所以e入队时做了处理
 79             if (limit+e.v*pow(e.a,-limit)+cost[e.to][N] < sum)
 80                 sum=limit+e.v*pow(e.a,-limit)+cost[e.to][N];
 81         }
 82         else
 83         {
 84             limit=cost[1][e.from];
 85             if (limit+e.v*pow(e.a,-limit)+cost[e.to][N] < sum)
 86                 sum=limit+e.v*pow(e.a,-limit)+cost[e.to][N];
 87         }
 88     }
 89 }
 90 int main()
 91 {
 92     while (scanf("%I64d%I64d",&N,&R)==2&&(R||N))
 93     {
 94         init();
 95         input();
 96         floyd();
 97         sum=cost[1][N];
 98         solve();
 99         printf("%.3lf\n",sum);
100     }
101     return 0;
102 }
时间: 2024-08-13 23:06:55

湖南省第6届程序大赛 Repairing a Road的相关文章

湖南省第6届程序大赛第3题 数字整除

题目C 数字整除 定理:把一个至少两位的正整数的个位数字去掉,再从余下的数中减去个位数的5倍.当且仅当差是17的倍数时,原数也是17的倍数 . 例如,34是17的倍数,因为3-20=-17是17的倍数:201不是17的倍数,因为20-5=15不是17的倍数.输入一个正整数n,你的任务是判断它是否是17的倍数. 输入 输入文件最多包含10组测试数据,每个数据占一行,仅包含一个正整数n(1<=n<=10100),表示待判断的正整数.n=0表示输入结束,你的程序不应当处理这一行. 输出 对于每组测试

湖南省第6届程序大赛第4题

题目D 台球碰撞 在平面直角坐标系下,台球桌是一个左下角在(0,0),右上角在(L,W)的矩形.有一个球心在(x,y),半径为R的圆形母球放在台球桌上(整个球都在台球桌内).受撞击后,球沿极角为a的射线(即:x正半轴逆时针旋转到此射线的角度为a)飞出,每次碰到球桌时均发生完全弹性碰撞(球的速率不变,反射角等于入射角). 如果球的速率为v,s个时间单位之后球心在什么地方? 输入 输入文件最多包含25组测试数据,每个数据仅一行,包含8个正整数L,W,x,y,R,a,v,s(100<=L,W<=10

湖南省第6届程序大赛第5题

题目E 内部收益率 在金融中,我们有时会用内部收益率IRR来评价项目的投资财务效益,它等于使得投资净现值NPV等于0的贴现率.换句话说,给定项目的期数T.初始现金流CF0和项目各期的现金流CF1, CF2, ...,CFT,IRR是下面方程的解: 为了简单起见,本题假定:除了项目启动时有一笔投入(即初始现金流CF0 < 0)之外,其余各期均能赚钱(即对于所有i=1,2,...,T,CFi> 0).根据定义,IRR可以是负数,但不能大于-1. 输入 输入文件最多包含25组测试数据,每个数据占两行

湖南省第6届程序大赛第二题 弟弟的作业

题目B 弟弟的作业 你的弟弟刚做完了“100以内数的加减法”这部分的作业,请你帮他检查一下.每道题目(包括弟弟的答案)的格式为a+b=c或者a-b=c,其中a和b是作业中给出的,均为不超过100的非负整数:c是弟弟算出的答案,可能是不超过200的非负整数,也可能是单个字符"?",表示他不会算. 输入 输入文件包含不超过100行,以文件结束符结尾.每行包含一道题目,格式保证符合上述规定,且不包含任何空白字符.输入的所有整数均不含前导0. 输出 输出仅一行,包含一个非负整数,即弟弟答对的题

湖南省第6届程序大赛第6题

Problem F Biggest Number You have a maze with obstacles and non-zero digits in it: You can start from any square, walk in the maze, and finally stop at some square. Each step, you may only walk into one of the four neighbouring squares (up, down, lef

湖南省第6届程序设计大赛第一题 汽水瓶

题目A 汽水瓶 有这样一道智力题:“某商店规定:三个空汽水瓶可以换一瓶汽水.小张手上有十个空汽水瓶,她最多可以换多少瓶汽水喝?”答案是5瓶,方法如下:先用9个空瓶子换3瓶汽水,喝掉3瓶满的,喝完以后4个空瓶子,用3个再换一瓶,喝掉这瓶满的,这时候剩2个空瓶子.然后你让老板先借给你一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板.如果小张手上有n个空汽水瓶,最多可以换多少瓶汽水喝? 输入 输入文件最多包含10组测试数据,每个数据占一行,仅包含一个正整数n(1<=n<=100),表示

湖南省第六届大学生计算机程序设计竞赛---汽水瓶

1006: 汽水瓶 时间限制: 1 Sec  内存限制: 128 MB 提交: 3  解决: 3 [提交][状态][讨论版] 题目描写叙述 有这样一道智力题:"某商店规定:三个空汽水瓶能够换一瓶汽水.小张手上有十个空汽水瓶.她最多能够换多少瓶汽水喝?"答案是5瓶,方法例如以下:先用9个空瓶子换3瓶汽水,喝掉3瓶满的,喝完以后4个空瓶子,用3个再换一瓶,喝掉这瓶满的,这时候剩2个空瓶子. 然后你让老板先借给你一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板.假设小张手上有n

湖南省第六届大学生计算机程序设计竞赛---数字整除

1008: 数字整除 时间限制: 1 Sec  内存限制: 128 MB 提交: 6  解决: 4 [提交][状态][讨论版] 题目描述 定理:把一个至少两位的正整数的个位数字去掉,再从余下的数中减去个位数的5倍.当且仅当差是17的倍数时,原数也是17的倍数 . 例如,34是17的倍数,因为3-20=-17是17的倍数:201不是17的倍数,因为20-5=15不是17的倍数.输入一个正整数n,你的任务是判断它是否是17的倍数. 输入 输入文件最多包含10组测试数据,每个数据占一行,仅包含一个正整

“青软杯”安徽科技学院第六届程序设计大赛_专业组

Contest - "青软杯"安徽科技学院第六届程序设计大赛_专业组 Start time:  2015-04-18 08:00:00.0  End time:  2015-04-18 12:00:00.0 Current System Time:  2015-04-21 00:07:42.57  Contest Status:   Ended 关于举办"青软杯"安徽科技学院 第六届程序设计大赛通知 ACM 国际大学生程序设计竞赛 (International Co