最近在洛谷上刷atc的动态规划而特此写的有一篇题解,希望有错误能得到大佬们的指点!
题目链接:Vacation - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目大意(摘自洛谷翻译):
太郎的暑假有n天,第i天他可以选择做以下三种事情:
- 游泳,获得ai点幸福值。
- 捉虫,获得bi点幸福值。
- 写作业,获得ci点幸福值。
但他不能连续两天进行同一种活动,请求出最多可以获得多少幸福值
由此题可知每一天只能做一种活动,因此我们列状态转移方程时转移的状态还要包括时间与进行哪些活动,即:
其中表示前i天且第i天进行第j个活动的最大值,由于连续两天不相同,我们可以枚举今天与前一天进行了哪些活动进行状态转移,最后记录这些状态的最大值,时间复杂度
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
using ll=long long ;
using pii=pair<int,int> ;
#define endl "\n"
constexpr int N=1e5+10;
constexpr int mod=1e9+7;
ll a[4][N];
ll dp[4][N];
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[1][i]>>a[2][i]>>a[3][i];
ll res=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=3;j++)
for(int k=1;k<=3;k++)
{
if(j!=k)
dp[j][i]=max(dp[j][i],dp[k][i-1]+a[j][i]);
res=max(res,dp[j][i]);
}
cout<<res<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
t=1;
while(t--)
solve();
return 0;
}
再说说这一道题的延申,我们改一下这道题限制条件, 当前一个活动的序号小于等于后一个活动的序号,就变成了P1854 花店橱窗布置:
题目链接:P1854 花店橱窗布置 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这里我简要只讲我的思路,详情可以做一做,这题目首先我们可以发现这题的状态转移方程并没有发生改变,,只不过只是所代表的含义变成了第i个花瓶擦第j种花的最大值,同时此题还要输出一个最大方案,这里我们不妨开个pre数组记录 上一瓶插哪朵花,这样我们可以顺着pre数组逆推回去,同时还要注意的一点在于再遍历第j种花时由于当前一个花与花瓶的序号小于等于后一个花与花瓶的序号,即说明在遍历时后一个状态只能在区间进行,而前一个状态只能在区间进行(要留下足够的花瓶),遍历一边即可,时间复杂度.