記幾個前一段遇到的幾個比較好玩的題目,以後再來回味~~
題目連結
在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題。