题目链接:HUASOJ 1776神奇的数组
对于这题,其实主要是通过运用数组解决问题。
同时也希望大家注意到数组不仅仅是用来存储数的,通过不同的定义方式配合一些递推式或者是规则就可以达到解决问题的目的。
PS:最近删了QQ数据,找不到之前老师发过的这题的解题图了,大家可以去群里搜索一下历史记录配合看。
比如说这道题,对于一个给定的数组,按规则选取任意个数,求所能取得数的最大和为多少。
把目光聚集到特定的某个位置上面,我们会发现,对于某一个特定位置的所能取得的结果,有且只有两种对应的答案:选取当前位置蛋糕所能得到的值,和不选取当前位置的蛋糕所能得到的值。
再把这个数放进数组中去看,我们又可以发现,对于某一个位置 a[i] ( 1 < i < n ),它的答案是和 a[i-1]的答案是相关的。
- 当取 a[i] 位置的时候 a[i-1] 位置的蛋糕是不可以取的
- 当不取 a[i] 位置的蛋糕时, a[i-1] 位置的蛋糕是可取可不取的(遵循贪心的 sy 的原则,我们肯定会选取一个其中值最大的一个(想想为什么))。
由此抽取出两条规则:
- a[i][1] = x + a[i-1][0]
- a[i][0] = max( a[i-1][0], a[i-1][1])
其中后缀[1]代表选取当前位置的蛋糕,否则就代表不选取,x 代表当前位置蛋糕的价值,max 代表取最大值的函数。
到了这里,一般的递推已经分析完了,关于递推式也已经给出来了,再往下看,我们发现对于每一个位置所能获得的价值可以由到它前一个位置所能获得的价值来递推过来的(得到取与不取两种情况下所得到的值)。
既然这样,那么对于第一个位置,它前面并没有其它的位置了,但是它的取与不取所能得到的值又是很明确的,所以可以考虑做个“特殊处理”:单独拿出来赋值。其实也还有另外的一种办法就是创建一个对应的“第零号位置”将其取与不取的值都赋为0,问题就解决了(大家自己想为什么)。
再贴下我的代码:
#include <iostream> //类似于C语言的<stdio.h>文件的作用
using namespace std; //使用命名空间std(想了解自行百度
int main(){
const int si = 1e4 + 9; //百度或者翻书查看const与后文定义数组的方法的关联
int a[si][2], r[si];
int n;
cin >> n; //相当于C语言scanf("%d",&n);
for(int i = 1; i <= n; i ++){
cin >> r[i]; //同上
}
a[0][0] = a[0][1] = 0; //初始化第零个位置为0
for(int i = 1; i <= n; i ++){
a[i][0] = max(a[i-1][0], a[i-1][1]);
a[i][1] = r[i] + a[i-1][0];
}
cout << max(a[n][1], a[n][0]); //相当于C语言printf("%d",max(a[n][1],a[n][0]);
return 0;
}
到这里1776就解决了,1777我也已经发布了,大家可以自愿的去试试(主要是看大家真的明白了这个思路的 a 数组的每一位的具体含义了没有,注意时间上的要求(关于时间的要求大家可以百度“时间复杂度”,有兴趣的还可以百度“空间复杂度”),我保证真的理解了这个思路的意思后,对于1777应该是可以解决了的。
最后,再次诚挚的邀请大家参加我们的“圣诞杯”活动,因为这个,我已经被骂“劝退”好多次了(来的人比往年少太多了),为此,我都不敢再去出赛题了……为了不让屠老师打我,大家能看到这儿的帮帮忙……报个名推个广吧……(感谢)