【SRM543 Div2 1000】 EllysThreeRivers
记几个前一段遇到的几个比较好玩的题目,以后再来回味~~
在Div1各种被虐,就开小号做Div2,遇到了这么一个题,题目意思很简单:
一个矩形区域竖直分为3部分,三条不同的河流,一个人从左下角游到右上角,在三条河中的速度不同v1,v2,v3,还有一个v是竖直沿河走的速度,问最小时间。
看到这个题目直接就想到了以前我出过的一个题目:忽略河的宽度的一个过河问题,出题时和Su_xing大神讨论到当考虑河宽度的时候可以根据一个定理来搞,也就是费马原理。
费马原理指出光在任意介质中从一点传播到另一点时,沿所需时间最短的路径传播。而这里我们要求最短路径,那么就可以依据光的折射法则。当时只提了一下猜想,也没去多想。这题不就是为这个定理而出的么,只要三分枚举第一次走时的角度,后面两条河走的角度都可以通过光线折射的方法去推出,然后竖直走到终点,取最小值就可以了。
1 #include <cstdlib> 2 #include <cctype> 3 #include <cstring> 4 #include <cstdio> 5 #include <cmath> 6 #include <algorithm> 7 #include <vector> 8 #include <string> 9 #include <iostream> 10 #include <sstream> 11 #include <map> 12 #include <set> 13 #include <queue> 14 #include <stack> 15 #include <fstream> 16 #include <numeric> 17 #include <iomanip> 18 #include <bitset> 19 using namespace std; 20 #define MIN(x,y) (x>y?y:x) 21 #define MAX(x,y) (x<y?y:x) 22 #define ABS(x) (x>0?x:(-x)) 23 #define PI (acos(-1)) 24 25 class EllysThreeRivers 26 { 27 public: 28 int l, wv; 29 vector<int> wl; 30 vector<int> sv; 31 32 double get(double r){ 33 double h = 0, t = 0; 34 h += double(wl[0])*tan(r); 35 t += double(wl[0])/cos(r)/double(sv[0]); 36 r = asin(double(sv[1])/double(sv[0])*sin(r)); 37 h += double(wl[1])*tan(r); 38 t += double(wl[1])/cos(r)/double(sv[1]); 39 r = asin(double(sv[2])/double(sv[1])*sin(r)); 40 h += double(wl[2])*tan(r); 41 t += double(wl[2])/cos(r)/double(sv[2]); 42 t += fabs(double(l)-h)/(double)wv; 43 return t; 44 } 45 46 double getMin(int length, int walk, vector <int> width, vector <int> swim){ 47 l = length; 48 wv = walk; 49 wl = width; 50 sv = swim; 51 52 double l = 0, r = PI/2.0; 53 double ll = (l*2.0+r)/3.0; 54 double rr = (l+r*2.0)/3.0; 55 while(rr-ll>1e-12){ 56 double lt = get(ll); 57 double rt = get(rr); 58 if(lt>=rt){ 59 l = ll; 60 }else{ 61 r = rr; 62 } 63 ll = (l*2.0+r)/3.0; 64 rr = (l+r*2.0)/3.0; 65 } 66 return get(rr); 67 } 68 };
可惜比赛时候脑残了,精度开小了 STF,赛后改了下精度就过了T-T
Div1的500不是这题,而是有多条河,只能走整数点的情况,貌似是一个要优化的DP题。