POJ2385 Apple catching(dp)

这篇博客介绍了POJ2385问题,即Farmer John的苹果接住游戏。Bessie需要在苹果落地前接住它们,题目给出了时间T、移动次数W和苹果掉落的顺序。博主使用动态规划的方法解决此问题,讨论了两种解法,一种是三维数组的状态转移方程,另一种是通过判断移动次数的奇偶性简化问题。博主分享了具体的代码实现。
摘要由CSDN通过智能技术生成

题意:Farmer John有两颗苹果树,分别编号为1和2,每棵树上都长满了苹果,Bessie无法摘到树上的苹果,所以只能等待苹果掉下来,厉害的是Bessie每次都能在苹果碰到地之前接住苹果,但前提是Bessie必须当前时刻在这颗树的下方,已知每分钟都有一颗树会掉落一个苹果,Bessie初始位置在第1颗树。现给出一个T代表总时间,W代表Bessie可以移动的次数,即从一颗树到另一颗树算移动一次。
7 2
2
1
1
2
2
1
1

6

数据解释: 一共有7分钟, 最多可以移动2次,第1分钟第2颗树掉落苹果,第2分钟第1颗树掉落苹果,第3分钟第1颗树掉落苹果,第4分钟第2颗树掉落苹果,第5分钟第2颗树掉落苹果,第6分钟第1颗树掉落苹果,第7分钟第1颗树掉落苹果。

Bessie在第1分钟不移动,依旧待在第1颗树,所以他可以接住第2,3分钟掉落的苹果,之后再第4分钟他移动到第2颗数,在第4分钟和第5分钟接住第2颗树掉落的苹果,之后再移动回第一颗树,接住最后两个苹果。

题解:我第一次做想着是一共有三个变量 时间,移动次数,树,所以我直接开了d[T][W][3]三维数组记录状态,d[T][W][1]代表在T时间,还剩下W次移动状态下到第1颗树时接住的总苹果树,d[T][W][2]就代表着第2颗树。

状态转移方程:
如果 w-1 >= 0
d[T][W][1] = max(d[T-1][W-1][2],d[T-1][W][1])
d[T][W][2] = max(d[T-1][W-1][1],d[T-1][W][2])
否则 d[T][W][1] = d[T-1][W][1];
如果a[i] == 1 d[T][W][1]++;
如果a[i] == 2 d[T][W][2]++;

初始化: T = 0时,肯定没有苹果可以接所以是0。

第二种解法:
可以省略掉第三维,仔细观察移动次数和树的关系,我们可以发现如果移动偶数次那么肯定还是在1号树,移动奇数次就是在2号树(因为初始在1号树)
所以在判断是否要++的时候可以用总w-当前剩余次数 = 移动的次数cnt。
cnt%2 +1 == a[i] 的话就说明此时有苹果可接,d[t][w]++。
贴一发第一次写的戳代码:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int a[1010];
int d[1010][40][3];
int main(){
    int t,w;
    cin >> t >> w;
    for(int i = 1; i <= t; ++i)
        cin >> a[i];
    memset(d,0,sizeof(d));
    for(int i = 1; i <= t; ++i){
        for(int j = 0; j <= w; ++j){
            if(a[i] == 1){
                int t = -1, t2 = -1;
                if(j-1 >= 0){
                    d[i][j][1] = max(d[i-1][j][1]+1,d[i-1][j-1][2]);
                    d[i][j][2] = max(d[i-1][j][2],d[i-1][j-1][1]+1);
                }
                else{
                    d[i][j][2] = d[i-1][j][2];
                    d[i][j][1] = d[i-1][j][1]+1;
                }

            }
            if(a[i] == 2){
                int t = -1, t2 = -1;
                if(j-1 >= 0){
                d[i][j][1] = max(d[i-1][j][1],d[i-1][j-1][2]+1);
                d[i][j][2] = max(d[i-1][j][2]+1,d[i-1][j-1][1]);

                }
                else{
                    d[i][j][1] = d[i-1][j][1];
                    d[i][j][2] = d[i-1][j][2]+1;
                }

            }

        }
    }
    int ans = -1;
    for(int i = 0; i <= w; ++i)
        ans = max(d[t][w][1],max(ans,d[t][w][2]));
    cout << ans << endl;
    return 0;
}
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int d[1010][40];
int a[1010];
int main(){
    int n,w;
    cin >> n >> w;
    memset(d,0,sizeof(d));
    for(int i = 1; i <= n; ++i)
        cin >> a[i];
    for(int i = 1; i <= n ; ++i)
        for(int j = 0; j <= w; ++j){
            if(j-1>=0)
                d[i][j] = max(d[i-1][j],d[i-1][j-1]);
            else
                d[i][j] = d[i-1][j];
            if((w-j)%2 + 1 == a[i])
                d[i][j]++;
        }
    int ans = -1;
    for(int i = 0; i <= w; ++i)
        ans = max(d[n][i],ans);
    cout << ans << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值