1. 程式人生 > >[HNOI2011]賽車遊戲

[HNOI2011]賽車遊戲

它的 vma 小時 發現 ont 折線 tro 復制 起點

題目描述

名歌手LAALA最近迷上了一款賽車遊戲,遊戲中開車的玩家在不同的路段需要選擇不同的速度,使得自己在最短的時間內到達終點。開始遊戲時,車內的初始油量為f,所以遊戲的關鍵是如何在速度和耗油量之間實現平衡。

LAALA 經過一段時間的研究後,發現這款遊戲可以用一個簡單的數學模型來描述,具體來說:從起點到終點的路線可以被簡化成折線段,每條線段代表一個上坡或者下坡,若在一段斜率為 s(s>0 代表上坡,s=0 代表平地,s<0 代表下坡)的道路上以速度 v km/h 行駛,則每公裏的耗油量為 max(0,av+bs),其中 a 和 b 為遊戲的內置參數,分別表示在平地行駛時的耗油率及斜坡對耗油量的影響(b 恒為正)。這裏假設,加速和減速不耗油,且看成是瞬間完成的,所以即使在同一條線段上也可采取以不同的速度行駛的策略來縮短耗費的時間。

由於 LAALA 在以前的遊戲中表現不佳,現在使用的車型依然是系統初始分配的,所以它的速度不能超過 vmax km/h。在獲得這些參數後,LAALA 想知道在初始油量受限的情況下(中途不許加油)自己能得到的最佳成績是多少。作為 LAALA 的歌迷,你能幫幫他嗎?

輸入輸出格式

輸入格式:

從文件input.txt中讀入數據,輸入文件的第一行是一個正整數T,表示數據組數。對每組數據,第一行是用空格隔開的4個浮點數a、b、vmax和f,其中a、b和vmax的意義如前所述,f表示初始油量,其單位也與前面的描述保持一致。第二行是一個正整數r,表示線段的數目。接下來的r行,每行是用空格隔開的2個浮點數xi和yi,分別表示在標準笛卡耳坐標系下該線段在水平方向和垂直方向的改變量(單位為米)。

輸出格式:

輸出文件 output.txt 包含 T 行,依次對應輸入中的 T 組數據。對某組數據,若基於初始油量無法到達終點,則對應行輸出 IMPOSSIBLE,否則輸出最少需要的時間(單位為小時)。

輸入輸出樣例

輸入樣例#1: 復制
3
10.0 1.0 150 0.0
1
100.0 -100.0
10.0100.0 150 1.0
2
1000
100100
0.50.110010
3
1000 0
100 10
100 -10
輸出樣例#1: 復制
1.41421
IMPOSSIBLE
0.07212

說明

【數據範圍】

100%的數據滿足 T≤100,0.1≤a≤100,0.1≤b≤100,10≤vmax≤200,0≤f≤50,r≤10000,1≤xi≤1000,-1000≤yi≤1000,且如果問題有解,那麽答案不超過 24。

你所輸出的答案需要恰好保留到小數點後 5 位,當且僅當你的輸出與標準答案完全一致時你的輸出才被視作正確。

在油耗中,b*k是定值,a*v在確定了v後也確定

那麽根據題意,在不考慮下坡的特殊性的情況下

速度越大,時間越少,油耗越接近f

此時$a*v=f-\sum_{i=1}^{n}b*k[i]$

但此時考慮下坡,因為對0取max

原本下坡油耗計算為負的變成0,也就是上式算出的v的油耗>f

單獨把油耗為負下坡稱作zyys坡

把zyys坡的v把變小沒用,因為總是0,所以只能減小其它坡的v,把zyys多出的油耗分走

因為zyys坡無論減不減小都是0,所以可以視為v

所以可以二分速度v,看是否滿足油量

在計算時間時要把zyys坡的速度取到油耗為0的最大臨界值:

當$a*v+b*k<=0$時,速度還可以往上提到臨界$min(vmax,-b*k/a)$

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 double eps=1e-15;
 8 double a,b,y[20001],x[20001],f,vmax,k[20001],l[20001];
 9 int n,T;
10 int fcmp(double x)
11 {
12   if (x>eps) return 1;
13   if (x<-eps) return -1;
14   return 0;
15 }
16 bool check(double mid)
17 {int i;
18   double sum=0;
19   for (i=1;i<=n;i++)
20     {
21       sum+=max(0.0,mid*a+k[i]*b)*l[i];
22       if (fcmp(sum-f)>0) return 0;
23     }
24   if (fcmp(sum-f)<=0) return 1;
25   return 0;
26 }
27 double cal(double mid)
28 {int i;
29   double tim=0;
30   if (mid<=eps) return 0;
31   for (i=1;i<=n;i++)
32     {
33       double tmp=a*mid+b*k[i];
34       if (tmp<=eps)
35     {
36       double v=min(vmax,-b*k[i]/a);
37       tim+=l[i]/v;
38     }
39       else
40     tim+=l[i]/mid;
41     }
42   return tim;
43 }
44 int main()
45 {int i;
46   cin>>T;
47   while (T--)
48     {
49       scanf("%lf%lf%lf%lf",&a,&b,&vmax,&f);
50       scanf("%d",&n);
51       for (i=1;i<=n;i++)
52     {
53       scanf("%lf%lf",&x[i],&y[i]);
54       x[i]/=1000.0;
55       y[i]/=1000.0;
56       k[i]=y[i]/x[i];
57       l[i]=sqrt(y[i]*y[i]+x[i]*x[i]);
58     }
59       double l=0,r=vmax,as=0,t=0;
60       while (t<=50)
61     {
62       t++;
63       double mid=(l+r)/2.0;
64       if (check(mid)) l=mid;
65       else r=mid;
66     }
67       as=cal(l);
68       if (as<=eps) printf("IMPOSSIBLE\n");
69       else printf("%.5lf\n",as);
70     }
71 }

[HNOI2011]賽車遊戲