题意
一条直线上有n个充电站(告诉你位置),乌龟刚开始有满电的电车,能开c距离,电动速度vt1,没电后脚踩速度vt2,到充电站可以选择充电,充电时间为t。
直线长l, 兔子速度为vr, 问乌龟有没有可能赢。
类型:
DP
思路:
my:
类似cf一题的思路
大体思路:把一段路合理分割,就可以把重叠的区间分开,然后就可以算出每段路的最小花费。最后寻找最短的拼接方法就好了。
首先状态压缩,节点为所有充电站的点和他们+c的点(另外:包含0和c)
然后对于每个点i,算出他们到之前的某个点j的最小花费cost[i][j]
然后 设dp[i]为到i号节点所需最小时间
状态转移为 dp[i] = min(dp[j] + cost[i][j]) (j = 0,1...i-1)
网:
dp[i]为从0到第i个充电站的最短时间(起点和终点都看做一个充电站)
dp[i] = min(dp[j] + cost[i][j]) (j = 0,1...i-1)
其中cost[i][j] 表示从j充电站 充满电 然后一路不停到i的时间。
应该说,网上的方法是我的方法在特殊情况下的解。
在状态转移上的差别在于,我的cost[i][j]表示j到i的最小花费
而网上的方法则是某个特定花费。
这个特定花费得到的思路是,当前状态,必然是由之前最后一个充电站来的。
抽象之,
我:当前状态的最优情况 由 之前某个状态 通过最优转移 得到。
网:当前状态的最优情况 必然由 之前某个状态 通过某种转移 得到。
简单的说:
网上这种思路的关键,就是找到,当前状态,必然是怎么来的。
寻找时需要置身于这种状态,然后想想他 必然 是怎么来。
如果没有必然,就是说怎么都有可能,那只能用最优转移的思路了。
收获总结
dp时
先找 必然转移 关系。
未果可以使用 最优转移 思路。
代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/************************************************************************* > File Name: hd2059.cpp > Author: Shine > Created Time: 2013-06-26 上午 9:16:42 > QuestionType: DP,离散化 > Way: ... > Submit: 1A > Gain: 最优转移 和 必然转移 > Experience: 优先考虑 必然转移 。因为最优转移很不好想。 ************************************************************************/ #include <iostream> #include <algorithm> using namespace std; int p[120]; int zip[300]; double zipGraph[300][300]; double dp[300]; inline double min(const double &a, const double &b) { return a < b ? a : b; } double dfs(int i) { if (dp[i] != -1) return dp[i]; double min = 9999999; //int finalj = -1; for (int j = i-1; j >= 0; j--) { //if (i <= j) cout<<"zipGraph reading ERROR! (i = "<<i<<", j = "<<j<<")"<<endl; if (dfs(j)+zipGraph[i][j] < min) { min = dfs(j) + zipGraph[i][j]; //finalj = j; } } //cout<<"i = "<<i<<" finalj = " << finalj << endl; return dp[i] = min; } int main() { int l, n, c, t, vr, vt1, vt2; while(cin >> l >> n >> c >> t >> vr >> vt1 >> vt2) { p[0] = 0; for (int i = 1; i <= n; i++) { cin >> p[i]; } //compress int tmp[300]; int i; for (i = 0; i <= n; i++) tmp[i+n+1] = (tmp[i] = p[i]) + c; sort(tmp, tmp+2*(n+1)); //for (int i = 0; i < 2*n+2; i++) { cout<<" "<<tmp[i]; }cout<<endl; zip[0] = tmp[0]; int zipp = 1; for (int i = 1; i < 2*(n+1); i++) { if (tmp[i] == tmp[i-1]) continue; if (tmp[i] >= l) break; zip[zipp++] = tmp[i]; } zip[zipp++] = l; //for (int i = 0; i < zipp; i++) cout<<" "<<zip[i]; //cout<<endl; //build zipGraph for (int i = zipp-1; i >= 0; i--) { for (int j = i-1; j >= 0; j--) { //if(i <= j) cout<<"zipGraph reading ERROR! (i = "<<i<<", j = "<<j<<")"<<endl; zipGraph[i][j] = (double)(zip[i] - zip[j])/vt2; } } int j = 0; //for (int i = j+1; i < zipp && zip[i] <= zip[j]+c; i++) { // if (i <= j) cout<<"zipGraph reading ERROR! (i = "<<i<<", j = "<<j<<")"<<endl; // zipGraph[i][j] = min(zipGraph[i][j], (double)(zip[i]-zip[j])/vt1); //} for (int pp = 0; pp <= n; pp++) { for (; zip[j] != p[pp]; j++); for (int i = j+1; i < zipp && zip[i] <= zip[j]+c; i++) { //if (i <= j) cout<<"zipGraph reading ERROR! (i = "<<i<<", j = "<<j<<")"<<endl; zipGraph[i][j] = min(zipGraph[i][j], (double)(zip[i]-zip[j])/vt1 + t*(j != 0)); } } //dfs find answer dp[0] = 0; for (int i = 1; i < zipp; i++) dp[i] = -1; //cout<<"( "<<dfs(zipp-1)<<" "<<(double)l/vr<<" )"<<endl; if (dfs(zipp-1) < (double)l/vr) cout << "What a pity rabbit!" << endl; else cout << "Good job,rabbit!" << endl; } return 0; }