题解 | #过河#

过河

https://www.nowcoder.com/practice/35ddfeb4e34f410bb9035682463a382f

#include <bits/stdc++.h>
using namespace std;

//此题解参考了 https://www.nowcoder.com/users/133865280 这位大佬的题解,尝试把他的思路解释得更加清晰

//若按照一般思路的dp,直接设开一个大小为L + 1的dp数组,其中dp[i]表示青蛙到达第i的位置时需要踩到的最小石头数量
//则设dp的全部数据初始化为inf,然后令dp[0] = 0,因为第i个位置只能由前[S,T]个位置跳达,因此状态转移方程为
//dp[i] = min(dp[i], dp[i-j] + hasStone? 0 : 1), j ∈ [S,T]
//这样会爆内存或者超时,主要原因是L 高达 10的9次方

//优化的思路,注意到L有10^9,而石头最多只有100个,也就是说每两个石子之间的距离可以长达10^7! 而中间这么多点都
//是没有石子的,因此不会对最终结果产生影响,就可以直接省略掉!对于两个石子之间距离特别大的情况(距离起码大于
//T)举例说明如下:
// i ...T+i ...2T+i ...3T+i ...... nT+i  j
// 设某两个石子的位置为i 和 j, 那么从i出发青蛙肯定能够达到的点为 kT+i (k=1...n),其中 j>= nT+i,其实根据
//状态转移方程不难发现,区间的值dp[kT+i+1, (k+1)T+i]和上一个区间dp[(k-1)T+i+1,kT+i]的值是一样的,也就是出现了重复
//和循环,因此只需要把n个长度为T的重复区间给优化剩下1个即可,这个可以通过取(j - i) mod T + T实现,注意这里最少要有一个T的长度,因为在这种情况下 ij之间的距离是大于T的

//i ... j .. T
//考虑另外一种情况,即i和j之间的距离小于等于T,则i和j之间的点都有可能跳到j,因此这些点得全部考虑,不能压缩

int main() {
    int L;
    int S, T, M;
    cin >> L >> S >> T >> M;
    vector<int> stones;
  //考虑出发点
    stones.push_back(0);
    int a;
    for(int i = 0; i < M; i ++){
        cin >> a;
        stones.push_back(a);
    }
  //考虑中点
    stones.push_back(L);
    sort(stones.begin(), stones.end());
    
    //cout << endl;
    //计算新的stone位置
    set<int> hasStone;
    //这是计算出来的新的桥的长度
    int l = 0;
    for(int i = 1; i < stones.size(); i ++){
        auto dis = stones[i] - stones[i - 1];
        //如果两个石子中间的距离小于T,则之间的点位都得考虑
        if(dis <= T){
            l += dis;
        //如果两个石子中间的距离大于T,则中间有很多段T的距离是不用考虑的可以直接mod T,只用考虑最后一段T到2T的距离
        }else{
            l += dis % T + T;
        }
        //记录新的石头位置, 首尾两端0 和 L的位置没有石头
        if(i > 0 && i < stones.size() - 1)
            hasStone.insert(l);
    }

    //因为青蛙最后可能会越过l,跳到l + T的后面,还要加上最后一段T
    int NL = l + T;

    //定义dp数组
    vector<int> dp(NL + 10, 100000);
    dp[0] = 0;
    for(int i = 1; i <= NL; i++){
        for(int j = S; j <= T; j ++){
            if(i >= j){
                dp[i] = min(dp[i], hasStone.count(i-j) == 0? dp[i-j] : dp[i-j] + 1);
            }
        }
    }
    auto ans = 100000;
    for(int i = l; i <= NL; i ++){
        ans = min(ans, dp[i]);
    }
    cout << ans;
}
// 64 位输出请用 printf("%lld")

全部评论

相关推荐

10-27 17:26
东北大学 Java
点赞 评论 收藏
分享
HNU_fsq:建议直接出国,这简历太6了。自愧不如
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务