#include
int a[1010][1010];
int max(int x,int y)
{
return (x>y)?x:y;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
scanf("%d",&a[i][j]);
}
}
for(int i=n-1;i>=1;i--)//
{
for(int j=1;j<=i;j++)//
{
a[i][j]+=max(a[i+1][j],a[i+1][j+1]);
}
}
printf("%d",a[1][1]);
return 0;
}
怎么说呢,重写一下之前的题,感觉自己思路还是没那么清晰,折腾了半天,没啥多余的想法,还是之前隐隐约约记得好像是要从下往上,今天认真的分析了一波:说实话,如果要我从上到下的话,我一看就觉得情况肯定巨多,所以我们可以逆向思维了,从下向上就可以将多变一,但是怎么从下往上呢? 从最后开始吧不行,情况还是多且不好分析,如果从最后一行开始每次都要两个往上看,所以最好的就是从倒数第二层开始,直接就对每个数的左下和右下进行分析,然后取大的和该数加起来,先将这两层的最佳情况合并为一,也就是加起来,然后再依次向上,每次都取最佳情况,最后留下来的最顶端的就是答案了。
然后再列列我自己再一次犯的错误,真的有时候偶尔犯的错不可怕,但是犯了第二遍就要注意了,这个错误很有可能在以后的很重要的时刻对你产生影响,所以要除之而后快,而我警示自己的方法就是把它写下来:
我刚刚就是把两个循环给越界了,这里解释一下加深自己的印象:
比如说,我在这里
for(int i=n-1;i>=1;i--)//
{
for(int j=1;j<=i;j++)//
{
a[i][j]+=max(a[i+1][j],a[i+1][j+1]);
}
}
i=n-1表示倒数第二层,没问题,后面的表示第一层,也就是从倒数第二层到第一层遍历,并且依次递减,一定要记得是依次递减,然后j=1表示从每行的第一个开始,由于我们可以发现第i行就有i个数,所以在第二个循环里面,j表示从第一个开始,到第i个结束,刚开始我不明白如果是这样的话,不就j+1越界了吗?但是别忘了,我们虽然求的是第i行,但是是从第i+1行里面比左右(其实实际输入的时候是在正下方和正下方的右边)哪个大,然后再加到i行的;
总结:对于这个动规里面的动态转移方程,要很清楚,你是在要求和还是求最大,别混了,然后就是是求的是上一状态还是下一状态,还是是本状态,最最最重要的是,当含有那下一状态和上一状态的时候,一定要注意是否会越界。
这个题再写一遍感觉对动规有了新的看法:
之前我一直觉得动规只是每步找最大然后将最大值打出来,其实他还有很变形的方式,它可以是求和,求余等等,自从学了二维数组优化为一维数组,我就已经开始飘了,公式模板一顿套,现在倒好,感觉有点被坑了,于是我就开始认真对待这道题:a few months later.....哈哈
先来看看这个题的的坑点:
1.每个人只能打一次,所以肯定是01背包,题目虽然没说,但是这是需要潜意识的。。。(反正我当时就没意识到);
2.一个人你不管打输还是打赢,都会有经验;
3.这个和普通01背包不一样,打输的经验可能会和打赢的一样多,这时候肯定二话不说直接选打输的,本来我考虑这么久,其实这里根本不用考虑这些,这里指要考虑价值也就是获得的经验,和取哪个无关,但是取打输了的是肯定的。只不过这串代码正好完成了这个任务,那它是怎么完成的呢?看完这个代码模拟一 遍既可以理解了:
#include
int dp[1010];
int win[1010],lose[1010];
int use[1010];
int max(int x,int y)
{
return (x>y)?x:y;
}
int main()
{
int n,x;
scanf("%d %d",&n,&x);
for(int i=1;i<=n;i++)
{
scanf("%d %d %d",&lose[i],&win[i],&use[i]);
}
for(int i=1;i<=n;i++)
{
for(int j=x;j>=use[i];j--)
{
dp[j]=max(dp[j]+lose[i],dp[j-use[i]]+win[i]);
}
for(int j=use[i]-1;j>=0;j--)
dp[j]+=lose[i];
}
printf("%lld",5*dp[x]);
return 0;
}
你会发现,这个代码其实和最基本的代码有一点的区别是,打输了也有经验,这就造成了什么情况呢,当拥有的药瓶不足够打败眼前的对手时,还是会获得经验,所以我们还是要求不足的情况下的价值,像平常的01背包优化后,我们其实是不用去算不足的情况的,为什么,正是由于算也相当于没算,没有价值......
最最最后,我们还是要去看
这时候我们就可以深刻的理解到:dp数组的优化后有很多好处但是也会有小小的瑕疵,好处就是大大缩小了空间的使用,有时候还是会缩少时间,但是他不能用于来知道我们选的物品的序号,还有就是没有计算空间不足的情况,这种优化在经典的01背包题里面当然可以,但是,在这种变形的就很容易踩坑。所以在优化的时候一定要慎重,代码是靠理解,而不是生硬套。
最后还是来个鸡汤吧!
少年的意气风发,是要看山看海看月亮。而奋斗的意义,是我拥有选择生活方式的能力,却依然留着出发时的心。我喜欢吃路边摊,但我要赚够能去大饭店的钱。因为这一生能用钱捍卫尊严的时刻,太多了