题目描述
cv工程师现在送你一个数组作为蓝桥杯结束的礼物,你可以从这个数组中选择任意多个不相邻的数字,请最大化你选择的数字之和。
数据范围:1≤n≤200000,−10^9≤ai≤10^9。
输入
第一行:一个数字 n 代表数组大小。
第二行:n 个数字,保证是整数(存在负数)。
输出
一个整数,表示你选择的数字之和。
输入输出样例
样例输入 #1
复制
4
2 1 1 1
样例输出 #1
复制
3
提示
小朋友,贪心不对哟
思路讲解:
这道题考察动态规划,首先我们要明白状态是什么,状态dp[i]表示以数字i作为最后一个数字的最大数字和,那么因为这道题要选择不相邻的数字,我们再来看状态转移,不相邻的数字也就意味着如果选择了第a[i]个数,第a[i-1]个数字一定不能选,从第1个数字到第i-2个数字都可以转移到第i个数字
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define int long long
const int N=200010;
int a[N];
int dp[N];
int maxsum;
signed main()
{
int n; cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++)
{
dp[i]=a[i];
for(int j=1;j<=i-2;j++)
{
dp[i]=max(dp[i],dp[j]+a[i]);
}
maxsum=max(maxsum,dp[i]);
}
cout<<maxsum<<endl;
return 0;
}
那么代码将会这么写,但你会发现TLE了,因为这道题n的数据范围非常的大,然后这个代码是n 方的时间复杂度,所以时间超限了。
优化:
(建议同学们可以先做一下问题 3144: 动态规划进阶题目之大盗阿福)
那么我们如何在O(n)的时间复杂度内解决这道题呢,
我们看,如果n为1的话,dp[1]=a[1];
n=2的哈,dp[2]=max(a[1],a[2]);
然后从3开始往后,他可能从前一个数直接转移过来,也可以从第i-2个数转移过来,dp[i-2]+a[i]
这道题有两个易错点:
1.这道题目的数字并非全部都是正数,也有负数,所以并不是选的数字越多越好,比如dp[3]的话,并不是选数字1和3 的和就比数字3要大,所以dp[3]更新的时候还要和a[3]做一下比较。
2.这道题目题干说的是选择任意多个不相邻的数字,这个任意多个就包括0个,也就是说,如果这些数字全是负数的话,你选数会越选越小,这时,你不如选择0个数字,这样的话,最大的和就是0了。
OK,上正确代码
AC代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define int long long
const int N=200010;
int a[N];
int dp[N];
signed main()
{
int n; cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
dp[1]=a[1];
dp[2]=max(a[1],a[2]);
for(int i=3;i<=n;i++)
{
dp[i]=max(a[i],max(dp[i-1],dp[i-2]+a[i]));
}
cout<<max((ll)0,dp[n])<<endl;
return 0;
}