动态规划——小朋友过河

动态规划——小朋友过河

小朋友过桥问题:在一个夜黑风高的晚上,有n(n <= 50)个小朋友在桥的这边,现在他们需要过桥,但是由于桥很窄,每次只允许不大于两人通过,他们只有一个手电筒,所以每次过桥的两个人需要把手电筒带回来,i号小朋友过桥的时间为T[i],两个人过桥的总时间为二者中时间长者。问所有小朋友过桥的总时间最短是多少。

问题分析:首先将n个小朋友按过河时间从小到大排序,设第i个小朋友过河的时间为T[i]。假设n个小朋友过河的总时间为f(n),则f(1)=T[1]; f(2)=T[2];f(3)=T[2]+T[1]+T[3]。
当n=4时,
1,2号小朋友过河,时间为T[2]
1号小朋友回来,时间为T[1]
3,4号小朋友过河,时间为T[4]
2号小朋友回来,时间为T[2]
此时,河这边仅有1,2号小朋友,时间为f(2)
所以过河总时间f(4) =T[2]+T[1]+T[4]+T[2]+f(2)

假设有n个小朋友(n>=4):
1,2号小朋友过河,时间为T[2]
1号小朋友回来,时间为T[1]
n-1,n号小朋友过河,时间为T[n]
2号小朋友回来,时间为T[2]
此时,河这边有1号到n-2号的所有小朋友,所以时间为f(n-2)
所以过河总时间f(n) =T[2]+T[1]+T[n]+T[2]+f(n-2)

通过以上表述我们可以得到如下递推公式:
f(1)=T[1]
f(2)=T[2]
f(3)=T[1] + T[2] + T[3]
f(n) = T[1]+2T[2]+T[n] + f(n-2); n>=4

实现代码如下:

#include <iostream>
#include <algorithm>
using namespace std;

int baby_cross_river(int *T, int n)
{
    if(n<=2) return T[n];
    if(n == 3) return T[1]+T[2]+T[3];
    int f_n2 = T[2]; //f(n-2)
    int f_n1 = T[1]+T[2]+T[3];//f(n-1)
    int f_n = 0;
    for(int i = 4; i <= n; ++i)
    {
        f_n = T[1] + 2*T[2] + T[i] + f_n2;
        f_n2 = f_n1;
        f_n1 = f_n;
    }
    return f_n;
}
int main()
{
    const int n = 5;
    int T[n+1]={0, 1, 2, 5, 10, 20};//start index = 1
    int fn = baby_cross_river(T, n);
    cout<<"total cost is "<<fn<<endl;
    return 0;
}

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
袋鼠过河问题是一个经典的动态规划问题,可以使用C语言来求解。假设有n个石头,编号为1~n,袋鼠要从石头1跳到石头n,每个石头上都有一个数字表示跳到该石头需要的体力值,袋鼠的体力值为m,每次跳跃可以跳1~k个石头,求袋鼠能否跳到石头n。 以下是使用C语言实现袋鼠过河问题的代码: ```c #include <stdio.h> #include <stdbool.h> bool canCross(int stones[], int n, int m, int k) { // 初始化动态规划数组 bool dp[n][m+1]; for(int i = 0; i < n; i++) { for(int j = 0; j <= m; j++) { dp[i][j] = false; } } dp[0][0] = true; // 动态规划 for(int i = 1; i < n; i++) { for(int j = 1; j <= m; j++) { for(int l = 1; l <= k && l <= i; l++) { if(stones[i] - stones[i-l] <= j) { dp[i][j] = dp[i][j] || dp[i-l][j-(stones[i]-stones[i-l])]; } } } } // 返回结果 for(int i = 0; i <= m; i++) { if(dp[n-1][i]) { return true; } } return false; } int main() { int stones[] = {0, 1, 3, 5, 6, 8, 12, 17}; int n = sizeof(stones) / sizeof(stones[0]); int m = 4; int k = 3; bool result = canCross(stones, n, m, k); printf("%s\n", result ? "能够跳到石头n" : "无法跳到石头n"); return 0; } ``` 在这个例子中,我们使用一个二维数组`dp`来记录动态规划状态,其中`dp[i][j]`表示袋鼠在第i个石头上,体力值为j时是否能够到达石头n。我们先将`dp[0][0]`初始化为true,表示袋鼠在第1个石头上时,体力值为0,可以到达石头n。 接下来,我们利用三重循环遍历所有可能的情况。第一重循环枚举所有的石头,第二重循环枚举所有可能的体力值,第三重循环枚举可以跳跃的石头个数。如果从第i个石头跳到第i-l个石头需要的体力值不超过j,那么我们就可以通过状态转移方程`dp[i][j] = dp[i][j] || dp[i-l][j-(stones[i]-stones[i-l])]`来更新`dp[i][j]`的值。最后,如果`dp[n-1][i]`中有任何一个值为true,那么就表示袋鼠可以跳到石头n。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值