UVA 11883 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
45, 1
ai
5), indicating that there is a bidirectional road connecting crossingxi 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.
题目大意:有一个C个点R条无向边(这俩字母好别扭……),每条边有一个花费vi和一个ai(浮点数)。现在我们有一个人,可以花费t(你爱多大就多大)的时间该修一条道路,什么时候开始修随你,修到什么时候随你,不过修的时候此路不通。如果总共修了t时间,那么这条路的花费就会变成vi * ai ^ (-t)。我们要从1走到C,求最小花费(花费就是时间)。
思路:首先要修路,肯定是从一开始就开始修,因为看出修得越久该路的花费就越少(不要告诉我你看不出那个是单调递减的函数),所以修的时间越长越好,而且,总不会说,我从这条路走过去了,然后你再开始修,修了一段时间,我再走一次,因为这都是无向边,根据最短路的性质一条边我们是肯定不会走两遍的,就算第二遍时间减少了也好。
其次,如果我们要修(x, y)这条边,我们要从x走到y,我们可能要先在x等一段时间,然后再从x走到y。我们等了一段时间再过去,路的花费也就减少了,可能要比我们直接走过去花的时间要更少。(样例真是业界良心……)
然后怎么办了,我们这里只有500条边,所以可以枚举每一条边,然后我们通过这一条边(可能从x到y也可能从y到x因为边是双向的,实际上大概有方法判定不过我懒……)。比如经过一条边(x, y)的最短路径就是dis(1, x) + (t - dis(1, x)) + vi * ai ^ (-t) + dis(y, C),第二个是可能站在x等待的时间,从最优的角度考虑t肯定是不会小于dis(1, x)。
其中dis(a, b)代表从a走到b所需要的最小花费。我们可以从1开始做单源最短路径,再从C开始做单源最短路径。嗯?C只有100?果断floyd,这太好写了。
设f(t) = dis(1, x) + (t - dis(1, x)) + vi * ai ^ (-t) + dis(y, C),怎么令这个f(t)最大呢?哦,不对,最小……首先我们可以观察一下这个函数,咳咳,观察不出来,求导吧……f'(t) = 1 - ln(ai) * vi * ai ^ (-t),求这个函数的零点,很好,这是一个单调的函数,果断二分求解0点。下界很简单,就是dis(1, x),那么上界呢?上界我们可以定为当前答案ans(初始化为dis(1, C)),因为如果修的时间比这个还多就没有意义了。问题是,这个是区间求零点,很可能没有零点,怎么办?如果零点在dis(1, x)的左边,那么t取dis(1, x)就好。如果在上界右边呢?这个我没分析也直接取了dis(1, x),因为我觉得应该不会出现要取上界右边这么坑爹的情况,反正就算取了它也不会是答案了,随便怎么样都无所谓了。
其实这上面的做法有个BUG,就是我可能从1走到x的时候,经过了边(x, y),然后其实修理(x, y)的时候我们并不能走(x, y)。但是为什么会AC呢?因为这种情况就算出现了,也肯定有比这个更优的答案,不予证明,反正我觉得是这样(咦,这个我好像前面就有提到过……)。
代码(32MS):
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std; const int MAXN = ;
const int MAXE = ;
const double EPS = 1e-; inline int sgn(double x) {
if(fabs(x) < EPS) return ;
return x > ? : -;
} double fpai(double t, double v, double a) {
//t - v * pow(a, -t)
return - log(a) * v * pow(a, - t);
} inline void update_min(double &a, const double &b) {
if(a > b) a = b;
} double mat[MAXN][MAXN];
int x[MAXE], y[MAXE];
double v[MAXE], a[MAXE];
int n, m; void floyd() {
for(int k = ; k <= n; ++k)
for(int i = ; i <= n; ++i)
for(int j = ; j <= n; ++j) update_min(mat[i][j], mat[i][k] + mat[k][j]);
} double find_t(int i, int x, int y, double l, double r) {
double L = l, R = r;
while(R - L > EPS) {
double mid = (L + R) / ;
//cout<<fpai(mid, v[i], a[i])<<endl;
if(fpai(mid, v[i], a[i]) > ) R = mid;
else L = mid;
}
if(sgn(fpai(L, v[i], a[i])) != ) return l;
return L;
} double solve() {
double t, ans = mat[][n];
for(int i = ; i < m; ++i) {
t = find_t(i, x[i], y[i], mat[][x[i]], ans);
update_min(ans, t + v[i] * pow(a[i], -t) + mat[y[i]][n]);
t = find_t(i, y[i], x[i], mat[][y[i]], ans);
update_min(ans, t + v[i] * pow(a[i], -t) + mat[x[i]][n]);
}
return ans;
} int main() {
while(scanf("%d%d", &n, &m) != EOF) {
if(n == && m == ) break;
for(int i = ; i <= n; ++i) {
for(int j = ; j <= n; ++j) mat[i][j] = 1e5;
mat[i][i] = ;
}
for(int i = ; i < m; ++i) {
int aa, bb; double cc;
scanf("%d%d%lf%lf", &aa, &bb, &cc, &a[i]);
x[i] = aa; y[i] = bb; v[i] = cc;
update_min(mat[aa][bb], cc);
update_min(mat[bb][aa], cc);
}
floyd();
printf("%.3f\n", solve());
}
}
UVA 11883 Repairing a Road(最短路径+暴力枚举)的更多相关文章
- HDU 3268/POJ 3835 Columbus’s bargain(最短路径+暴力枚举)(2009 Asia Ningbo Regional)
Description On the evening of 3 August 1492, Christopher Columbus departed from Palos de la Frontera ...
- UVA 617 - Nonstop Travel(数论+暴力枚举)
题目链接:617 - Nonstop Travel 题意:给定一些红绿灯.如今速度能在30-60km/h之内,求多少个速度满足一路不遇到红灯. 思路:暴力每个速度,去推断可不能够,最后注意下输出格式就 ...
- UVA 11059 Maximum Product【三层暴力枚举起终点】
[题意]:乘积最大的子序列.n∈[1,10],s∈[-10,10] [代码]: #include<bits/stdc++.h> using namespace std; int a[105 ...
- UVA.12716 GCD XOR (暴力枚举 数论GCD)
UVA.12716 GCD XOR (暴力枚举 数论GCD) 题意分析 题意比较简单,求[1,n]范围内的整数队a,b(a<=b)的个数,使得 gcd(a,b) = a XOR b. 前置技能 ...
- UVA 10012 How Big Is It?(暴力枚举)
How Big Is It? Ian's going to California, and he has to pack his things, including his collection ...
- uva 11088 暴力枚举子集/状压dp
https://vjudge.net/problem/UVA-11088 对于每一种子集的情况暴力枚举最后一个三人小组取最大的一种情况即可,我提前把三个人的子集情况给筛出来了. 即 f[S]=MAX{ ...
- UVA - 11464 Even Parity 【暴力枚举】
题意 给出一个 01 二维方阵 可以将里面的 0 改成1 但是 不能够 将 1 改成 0 然后这个方阵 会对应另外一个 方阵 另外一个方阵当中的元素 为 上 下 左 右 四个元素(如果存在)的和 要求 ...
- 紫书 例题 10-2 UVa 12169 (暴力枚举)
就是暴力枚举a, b然后和题目给的数据比较就ok了. 刘汝佳这道题的讲解有点迷,书上讲有x1和a可以算出x2, 但是很明显x2 = (a * x1 +b) 没有b怎么算x2?然后我就思考了很久,最后去 ...
- 湖南省第6届程序大赛 Repairing a Road
Problem G Repairing a Road You live in a small town with R bidirectional roads connecting C crossing ...
随机推荐
- java的引用总结
四种引用:强弱软虚 强引用:使用强引用,在内存不足的时候垃圾处理器也不会回收他,哪怕导致程序崩溃 例如: A a=new A() 软引用:内存不足的时候会被回收(软引用可以和一个引用队列(Refere ...
- JS JavaScript事件循环机制
区分进程和线程 进程是cpu资源分配的最小单位(系统会给它分配内存) 不同的进程之间是可以同学的,如管道.FIFO(命名管道).消息队列 一个进程里有单个或多个线程 浏览器是多进程的,因为系统给它的进 ...
- Git工作流指南:Gitflow工作流
git工作流 1.Git flow 核心分支:master,dev 可能还会有:功能分支,bug修复分支,预发布分支 2.github flow:只一个长期分支,就是master 第一步:根据需求,从 ...
- dcm4che 的依赖无法下载
遇到问题时我在Gradle这样引入 maven { url "http://www.dcm4che.org/maven2"} 这样使用可以解决问题 maven { url &quo ...
- Linux进程间通信---管道和有名管道
一.管道 管道:管道是一种半双工的通信方式,数据只能单方向流动,而且只能在具有亲缘关系的进程间使用,因为管道 传递数据的单向性,管道又称为半双工管道.进程的亲缘关系通常是指父子进程关系. 管道的特点决 ...
- 构建高可靠hadoop集群之5-服务级别授权
本人翻译自: http://hadoop.apache.org/docs/r2.8.0/hadoop-project-dist/hadoop-common/ServiceLevelAuth.html ...
- C# Winform WebBrowser控件
C# WinForm WebBrowser 1.主要用途:使用户可以在窗体中导航网页. 2.注意:WebBrowser 控件会占用大量资源.使用完该控件后一定要调用 Dispose 方法,以便确保及时 ...
- 10---git安装
卸载原来的版本: # 查看版本 git --version # 移除原来的版本 yum remove git 安装依赖库: yum install curl-devel expat-devel get ...
- react中事件冒泡之填坑
今天在写个组件,大致代码是这样的: class Switch extends React.Component { handlerChange = (e) => { const {onChange ...
- 笔记-flask-原理及请求处理流程
笔记-flask-原理及请求处理流程 1. 服务器声明及运行 最基本的flask项目代码如下 from flask import Flask app = Flask(__name__) @a ...