HDU 2059:龟兔赛跑

题意

一条直线上有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时

先找 必然转移 关系。

未果可以使用 最优转移 思路。

代码

/*************************************************************************
    > 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;
}
View Code

 

 

posted on 2013-06-26 13:08  ShineCheng  阅读(256)  评论(0)    收藏  举报

导航