P2690 [USACO04NOV]Apple Catching G

https://www.luogu.com.cn/problem/P2690
涉及知识点:动态规划DP,搜索
黄色题
 
思路:

这道题简单的地方有两个:一是数据范围小,二是在不用管大小的情况下方程十分好想。但仍然有一些小细节让我错了两回。 分析过程:

1.问啥设啥。

......时的最大接苹果数;这里我们发现题目设定上有两个比较明显的变量:总数和移动次数。于是先无脑把他们设出来!于是得

f[落下多少个][移动几次];

2.想转移方程,进行补充。

那么这个方程的上一种状态是什么呢?首先捡不捡不一定,但上种状态落下的果子肯定少一,所以第一维是i-1;那么他到底有没有移动呢?我们自然会想到会有以下情况: ①他从另一棵树移过来并且接到了果子;

②他从另一棵树移过来但没接到果子;

③他站着不动接到了一颗果子;

④他站着不动也没接到果子;

但他到底有没有接到果子呢???我们并不知道他现在在哪里,所以也不知道他有没有接到果子,于是我们决定多加一维来表示他所在的位置。于是得

f[落下多少个][移动次数][现在所处位置]

我发现人刚开始在第一棵树下,那就意味着移动奇数次时人一定在二号树下,偶数次时人一定在一号树下!二者不能同时被修改!所以方程改为:

if(a[i]==1)
{
    if(j%2==0)   f[i][j][1]=max(f[i-1][j-1][2],f[i-1][j][1])+1;
    else   f[i][j][2]=max(f[i-1][j][2],f[i-1][j-1][1]);
}           
if(a[i]==2)
{
    if(j%2==1)  f[i][j][2]=max(f[i-1][j-1][1],f[i-1][j][2])+1;
    else   f[i][j][1]=max(f[i-1][j][1],f[i-1][j-1][2]);
}

但移动次数越多并不代表接到的苹果数越多,所以要遍历所有移动次数找最大值

#include<bits/stdc++.h>
using namespace std;
int t,w;
int a[1009];
int f[1009][35][3];//落到第几个,移动几次,当前在哪棵树下 
///时的最大接苹果数 
int main()
{
    cin>>t>>w;
    for(int i=1;i<=t;i++){
        cin>>a[i];
    }
    for(int i=1;i<=t;i++){
        for(int j=0;j<=w;j++){
            if(a[i]==1)
            {
                if(j%2==0)//偶数 
                {
                    f[i][j][1]=max(f[i-1][j-1][2],f[i-1][j][1])+1;
                }
                else 
                f[i][j][2]=max(f[i-1][j][2],f[i-1][j-1][1]);
            }
            if(a[i]==2)
            {
                if(j%2==1)
                {
                    f[i][j][2]=max(f[i-1][j-1][1],f[i-1][j][2])+1;
                } 
                else 
                f[i][j][1]=max(f[i-1][j][1],f[i-1][j-1][2]);
            }
        }
    } 
    int ans=-1;
    for(int j=0;j<=w;j++)
    {
        ans=max(ans,max(f[t][j][1],f[t][j][2]));
    }
    cout<<ans;
    return 0;
}

注:在前一时刻i-1中,只有两种情况可以到达f[i][j][1]

一. f[i-1][j][1]

二.f[i-1][j-1][2]
posted @ 2022-07-25 19:35  -イレイナ  阅读(107)  评论(0)    收藏  举报