描述 Description
一辆重型卡车欲穿过S公里的沙漠,卡车耗汽油为1升/公里,卡车总载油能力为W公升。显然卡车装一次油是过不了沙漠的。因此司机必须设法在沿途建立若干个贮油点,使卡车能顺利穿过沙漠。试问司机如怎样建立这些贮油点?每一贮油点应存储多少汽油,才能使卡车以消耗最少汽油的代价通过沙漠?
输入格式 Input Format
仅一行,读入整数S,W(S<=1000,W<=500)。
输出格式 Output Format
编程计算及打印建立的贮油点序号,各贮油点距沙漠边沿出发的距离以及存油量(输出到小数点后第二位)。
样例输入 Sample Input
1000 500
样例输出 Sample Output
0 0.00 3881.36
1 22.43 3500.00
2 60.89 3000.00
3 106.35 2500.00
4 161.90 2000.00
5 233.33 1500.00
6 333.33 1000.00
7 500.00 500.00
这道题可能有很多人一开始看不懂题目的意思,所以有必要先声明一下:
就是说一辆车子想要穿过沙漠,但是一次肯定肯定通过不了,因为油箱的油是不够的,所以我们需要在沿途建立一系列贮油点,注意,汽车边通过 贮油点也是边建立的。
就比如说样例:沙漠全长1000km,油箱容量为500L。输出就是说我们首先在起点(标号为0)建立一个3881.36L的贮油点,接下来我们将在距离起点22.43千米的位置(标号为1)建立一个含有3500L油的贮油点,一共跑了17次单程,消耗了381.36L的油,前一个(起点)贮油点的油已经全运过来了,然后把剩下的3500L油运向下一个贮油点......直到最后一个贮油点剩余500L油,油箱一次加满刚好跑完剩下的500km。
可见,车子是边走边建立储油点的,车子离开的时候,每个储油点的油都被运到了下一个储油点,到最后车子离开沙漠,油全部用完。我们要求的就是每个贮油点的信息。(消耗最少汽油的代价通过沙漠)
解题思路:
如果从起点出发顺推,则我们无法确定第一个贮油点的位置及贮油量,因此我们可以用倒推法来解决这个问题:先从终点出发倒推最后一个储油点的位置及储油量,然后再把最后一个储油点作为终点,倒推倒数第二个储油点的位置及储油量。
就拿样例来说,如果从头向后遍历的话,用DP不可行,因为没有说明其单位长度,而且DP的复杂度过高,所以从后向前考虑。在最优条件下,应该是卡车在前500米用光所有的油,然后在500米处灌满500L,再跑完剩下的500米,这样保证了最后消耗最少的汽油通过沙漠。所以目前明确在距离终点500米处要建一个500L的储油点。假设这个储油点左边X公里有一个储油量无限大的储油点,从此储油点不断搬运,使得这个500米处的储油点具有500L。那么以最优条件下,需要向储油点灌两次油,因为一次是肯定运不到这么多的。第一次:灌500-2xL的油(因为灌完要回来);第二次:灌500-xL的油(灌满就不用管了),求得x=500/3。可知跑的这两次一共灌了1000L油(灌满油箱两次),所以在距离终点500+500/3km的位置需要修建1000L的储油点。以此向前递推,直到到达起始点。
代码实现如下:
#include<bits/stdc++.h> using namespace std; double dis[1010],gas[1010],last,w; int s,cnt,x; int main() { cin>>s>>w; dis[1]=s-w; gas[1]=w; last=dis[1];cnt=1;x=1; while(last!=0) { cnt++; x+=2; dis[cnt]=dis[cnt-1]-w/x; gas[cnt]=gas[cnt-1]+w; last=dis[cnt]; if(last<0) { cnt--;break; } } dis[cnt+1]=0; gas[cnt+1]=dis[cnt]*(x+2)+gas[cnt];//最后一次手动处理(起点) for(int i=cnt+1;i>=1;i--)printf("%d %.2lf %.21lf ",cnt-i+1,dis[i],gas[i]); return 0; }