看了一些博客,这句话印象最深刻:
DP题。理解DP不是一种固定的算法,而是一种思路,是一种用空间换时间的思维方式。开数组记录每一步的最优解,每次比较更新,最后得出的就是整体最优解。
这题每个步骤有个决策,就是在充电站时选择充或不充,每个决策有影响后面的决策。然后就是怎样让每一步达到最优,这时就要用数组记录然后更新,用一个数组记录每一步的最优解,然后再根据决策的不同,将所有可能的情况列出得这一步的最优解,再保存,下来重复操作。这样最后的到的解就为整体的最优解。
思路:dp[i]:记录到站点i的最短时间,从0 - (i-1) 判断确定加油后到i的时间,因为到i点肯定是由0-(i-1)中的某一点加了油后不再加油直接到达i点最优(即肯定有一个最后加油点)。可能会有疑问,如果之前到某一点 j 时还有余量,那再加油判断是不是会有问题呢?其实不会,如果到j你不加油,那肯定是之前的某k点加油了,而那点dp[k]已计算过了,所以不再考虑j点不加油的情况,所以一直dp下来即可求出到达终点的最短时间。
dp是一种拿空间换时间的做法,但是状态的每一个特性不可能全部记录下来,那么只挑选有决定性的(思考二维背包到底是哪二维度,dp又记录了什么)。
所以dp也必然含有那么一点贪心的思路。
#include<iostream>
using namespace std;
#define INF 100000000
int main()
{
int l,n,c,t,vr,v1,v2,p[110];
double t1,t2,dp[110],min; //dp[i]表示到第i个充电站所用最少的时间
int i,j,temp;
while(cin>>l)
{
scanf("%d%d%d%d%d%d",&n,&c,&t,&vr,&v1,&v2);
for(i=1;i<=n;i++)
cin>>p[i];
p[0]=0; //将起点当做第0个充电站
p[n+1]=l; //将终点当做第n+1个充电站
dp[0]=0;
for(i=1;i<=n+1;i++)
{
min=INF;
for(j=0;j<i;j++)
{
temp=p[i]-p[j];
if(temp>c)
t2=1.0*c/v1+1.0*(temp-c)/v2;
else
t2=1.0*temp/v1;
t2+=dp[j];
if(j) //有充电
t2+=t;
if(min>t2) //找最小的时间
min=t2;
}
dp[i]=min;
}
t1=1.0*l/vr; //兔子用的时间
if(t1>dp[n+1])
printf("What a pity rabbit!\n");
else
printf("Good job,rabbit!\n");
}
return 0;
}