[HDU] 2059 龟兔赛跑 有点暴力性质的dp
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> //#include<math.h> //#include<algorithm> //#include<queue> //#include<stack> using namespace std; int const MAX =0x3f3f3f3f; struct state { int remainDriving; int divingDist; int fDist; double time; }; int main() { int totalLengh; int chargerCount,drivingDist,chargingDuration; int r_speed,t_dSpeend,t_fSpeed; int dist[102]; while(scanf("%d",&totalLengh)!=EOF) { state dp[102][102]; memset(dp,0,sizeof(dp)); scanf("%d %d %d",&chargerCount,&drivingDist,&chargingDuration); scanf("%d %d %d",&r_speed,&t_dSpeend,&t_fSpeed ); for(int i=1;i<=chargerCount;i++) scanf("%d",&dist[i]); dist[0]=0; dist[chargerCount+1]=totalLengh; dp[0][0].divingDist=0; dp[0][0].fDist=0; dp[0][0].remainDriving = drivingDist; dp[0][0].time=0.0; for(int i = 1;i<=chargerCount+1;i++) { double minTime = MAX+0.0; int minIndex; for(int j=0;j<i;j++) { if(dp[j][i-1].remainDriving <= dist[i]-dist[i-1]) { dp[j][i].divingDist = dp[j][i-1].remainDriving; dp[j][i].fDist = dist[i]-dist[i-1]-dp[j][i-1].remainDriving; dp[j][i].remainDriving = 0; } else { dp[j][i].divingDist = dist[i]-dist[i-1]; dp[j][i].fDist = 0; dp[j][i].remainDriving = dp[j][i-1].remainDriving -(dist[i]-dist[i-1]); } dp[j][i].time = dp[j][i-1].time + (double)dp[j][i].divingDist/(double)t_dSpeend + (double)dp[j][i].fDist/(double)t_fSpeed; if(minTime>dp[j][i].time) { minTime = dp[j][i].time; minIndex = j; } } dp[i][i].divingDist = dp[minIndex][i].divingDist; dp[i][i].fDist = dp[minIndex][i].fDist; dp[i][i].time = dp[minIndex][i].time+(double)chargingDuration; dp[i][i].remainDriving = drivingDist; } double temp = (double)MAX; for(int i=0;i<chargerCount+1;i++) { if(dp[ i][chargerCount+1].time<temp) temp = dp[i][chargerCount+1].time; } double r_t = (double)totalLengh/(double)r_speed; if(r_t>temp) cout<<"What a pity rabbit!"<<endl; else cout<<"Good job,rabbit!"<<endl; } return 0; }
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2059
方法:设F(i,n) (0<=i<n)来表示当到达第n个加油站的时候,在前面的n-1个加油站中的第i个加油站加油其他加油站不加油的前进情况,i的0表示是刚出发的那个位子,把那个位子也模拟成一个加油站,当然它只有一个选择,那就是加满了油的。这些前进情况包含几个信息:从上一个加油站到此骑车前进的距离drivingDist,从上一个加油站到此步行前进的距离fDist,从开始到此一共花的时间time以及当前还剩余多少距离可以骑车前进remainDriving。
当i==n的时候,这个表示成在该站要加油,这个时候,需要消耗的时间当然是以上状态中最快的那个时间加上加油的时间,因为不管以上状态还,还可以继续骑车的距离有多么不同,只要一加了油,都会同一继续骑车的剩余距离,那就是加满油的骑车前进距离。既然如此那当然选择以上状态中最快的一个F(fastest,n),这样的选择其实就会涵盖前面几个加油站加油还是不加油,是连续几个加油站都加油还是怎么这些组合可能的考虑,最后设置加油后的前进状态。设两个加油站k,j间的距离为S(k,j)
状态转移方程:
{
[
drivingDist = F(i,n-1).remainDriving >= S(n-1,n) ? S(n-1,n): F(i,n-1).remainDriving,
remainDriving = F(i,n-1).remainDriving >= S(n-1,n) ? F(i,n-1).remainDriving-S(n-1,n): 0,
fDist = F(i,n-1).remainDriving >= S(n-1,n) ? 0:S(n-1,n)-F(i,n-1).remainDriving,
time = F(i,n-1).time + drivingDist/骑车速度 + fDist/步行速度
], 0<=i<n;
F(i,n) = [
除 time外的所有信息都和F(fastest,n) 的相同,
time = Min({ F(i,n).time | 0<=i<n}) + 加油消耗时间
], i==n;
}
而最后问题的解为:Min( {F(i,N).time | 1<=i<=N})
最后拿这个解去和兔子比速度。
感谢:细心,注意小数运算。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> //#include<math.h> //#include<algorithm> //#include<queue> //#include<stack> using namespace std; int const MAX =0x3f3f3f3f; struct state { int remainDriving; int divingDist; int fDist; double time; }; int main() { int totalLengh; int chargerCount,drivingDist,chargingDuration; int r_speed,t_dSpeend,t_fSpeed; int dist[102]; while(scanf("%d",&totalLengh)!=EOF) { state dp[102][102]; memset(dp,0,sizeof(dp)); scanf("%d %d %d",&chargerCount,&drivingDist,&chargingDuration); scanf("%d %d %d",&r_speed,&t_dSpeend,&t_fSpeed ); for(int i=1;i<=chargerCount;i++) scanf("%d",&dist[i]); dist[0]=0; dist[chargerCount+1]=totalLengh; dp[0][0].divingDist=0; dp[0][0].fDist=0; dp[0][0].remainDriving = drivingDist; dp[0][0].time=0.0; for(int i = 1;i<=chargerCount+1;i++) { double minTime = MAX+0.0; int minIndex; for(int j=0;j<i;j++) { if(dp[j][i-1].remainDriving <= dist[i]-dist[i-1]) { dp[j][i].divingDist = dp[j][i-1].remainDriving; dp[j][i].fDist = dist[i]-dist[i-1]-dp[j][i-1].remainDriving; dp[j][i].remainDriving = 0; } else { dp[j][i].divingDist = dist[i]-dist[i-1]; dp[j][i].fDist = 0; dp[j][i].remainDriving = dp[j][i-1].remainDriving -(dist[i]-dist[i-1]); } dp[j][i].time = dp[j][i-1].time + (double)dp[j][i].divingDist/(double)t_dSpeend + (double)dp[j][i].fDist/(double)t_fSpeed; if(minTime>dp[j][i].time) { minTime = dp[j][i].time; minIndex = j; } } dp[i][i].divingDist = dp[minIndex][i].divingDist; dp[i][i].fDist = dp[minIndex][i].fDist; dp[i][i].time = dp[minIndex][i].time+(double)chargingDuration; dp[i][i].remainDriving = drivingDist; } double temp = (double)MAX; for(int i=0;i<chargerCount+1;i++) { if(dp[ i][chargerCount+1].time<temp) temp = dp[i][chargerCount+1].time; } double r_t = (double)totalLengh/(double)r_speed; if(r_t>temp) cout<<"What a pity rabbit!"<<endl; else cout<<"Good job,rabbit!"<<endl; } return 0; }