自信既是强大,祝大家考试顺利丫
本题题意:
从三角形的顶部到底部有很多条不同的路径。你的任务就是找到最大的和。
路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数。
此外,向左下走的次数与向右下走的次数相差不能超过 1。
这题是比较简单的DP,只是要进行简单的分类标记不可能走到的地方即可
由于本人是懒死的(确石),详细请看讨论区QAQ
//这里我是用自下到上进行的累加
#include<cstdio>
using namespace std;
const int N = 104;
int f[N][N], n,s;
inline int max(int &a,int &b){return a < b ? b : a;}
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; i++){
for(int j = 1 ;j <= i; j++){
scanf("%d",&f[i][j]);
if(i>(n+2) >> 1) // 按 题目意思即可
if(j < (((n-1) >> 1)+i-n+1) || j > ((n >> 1)+1)) f[i][j]=-1;
}
}
//状态转移方程: 找最大值即可
for(int i = n - 1; i > 0; i--)
for(int j = 1; j <= i;j ++)
f[i][j] += max( f[i+1][j], f[i+1][j+1]);
printf("%d\n", f[1][1]);
return 0;
}
建议配套食用
这题就更简单了,不需要进行一些细节处理,但是为了照顾想我一样比较菜的童鞋,我就写仔细点
1:DFS:把所有的路径都走一遍,找最大值
//朴素DFS
void dfs(int x,int y,int cnt){
//表示从(x,y)的步数是cnt ,要去下一个点
if(x == n){
if(cnt > ans) ans = cnt; //ans表示总的最大值
return ;
}
dfs(x+1,y,cnt+a[x+1][y]);
dfs(x+1,y+1,cnt+a[x+1][y+1]);//两个方向:下和右下
}//很明显很多事重复的,时间复杂度O(2的n-1次方),(比较菜,markdown语法没学咋地);
//记忆化DFS
void dfs(int x,int y){
if(!f[x][y] ){ //没有调用过
if(x == n) f[x][y] = a[x][y];
else f[x][y] = a[x][y] + max(dfs(x+1,y),dfs(x+1,y+1) );
}
return f[x][y]; //已经调用过就直接输出
}
2.DP
- 这题就从上到下累加吧, 但是累加之后答案在最后一行,还要进行比较才能的到答案 即答案在f[n][1~n]中;
- 确定状态: f[x][y] 表示从(1,1)到(x,y)的最大和, 答案就在最后一行ans = max( f[1][n], f[2][n],f[3][n]… )
- 两种状态:向下和向右下:
- 状态状态方程: f[x][y] = max(f[x-1][y],f[x-1][y-1]) + a[i][j];
//这里我就用自下倒上的了,自上到下就留个读者思考吧
#include <iostream>
using namespace std;
const int N = 1005;
inline int max(int & a, int & b){return a < b ? b : a;}
int f[N], a[N][N], n;
int main(){
cin>>n;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= i; j++)
cin>>a[i][j];
for(int i = n ; i >= 1; i--)
for(int j = 1; j <= i; j++)
f[j] = max(f[j], f[j+1]) + a[i][j];
// cout<<f[i]<<endl;
cout<<f[1]<<endl;
return 0;
}
兄弟,最后一个Dp写错了hh
最后一个dp不是这道题的,是另外一道题的,我在中间那放了题目链接,是那道题的。
想问一下大佬 if(j < (((n-1)>>1)+i-n+1) || j > ((n>>1)+1))
这一步中判断J能不能走的式子的具体含义是什么呀,不知道它怎么得出的
最近比较忙,没看见,请见谅就直接用样例来讲吧:
你可以看见并不是所有的
if(i > (n+2) >> 1)
行都被标记。其实这里和i
的分析方法是一样的。如果你一直向右下走的话, 要满足
向左下走的次数与向右下走的次数相差不能超过 1
那你向右下
与向下
相差不能超过1
(大于或者小于1);例如这个样例,如果你要走到
第4行第3个
数字你就只能向右下走2步
,并且向下走1步
(虽然顺序可以不同,但是总的步数是一样的),如果你要走到第四行第四个
,你只能向右下走3步
,很明显是不行的,故标记不可能走到你可以发现当
向右下走超过(n >> 1)+1)
时是不可能的(向右下走的步数比向下走的步数大了不止1),向下走低于((n-1) >> 1)+i-n+1
时也是不可能的(向下走的步数比向右下走的步数大了不止1)这个都是我不知道是什么时候写的题解了,好乱啊,下次有空改一下吧,哈!
这里是排除不能去到的点吧,想问一下大佬是怎么得到这几个式子的
对的对的,
哈哈,这是精髓啊,这都被你发现了,有进国赛的潜力,Orz对于这个代码:
if(i>(n+2)/2) if(j < (((n-1)>>1)+i-n+1) || j > ((n>>1)+1)) f[i][j] = -1;
(n+2)/2
是上取整,为什么要这样判断的??## 划重点!!
因为原文中题目的要求是
此外,向左下走的次数与向右下走的次数相差不能超过 1。
这个很重要,解题的关键来看一下样例
为了满足要求我们
向下
走(原文是向右下,但其实谁数据就成向下了)和向右
下走步数不超过 1
那你看看可不可能到第
4
行的2
, 不可能!!,为什么??勘误:
但其实谁数据就成向下了
应该是
但其实输入和处理数据时就成向下走了
苏,时间的回旋镖来了,希望你看到这条评论,别问我是谁,我也不知道你是谁,题解写的很好,使我的大脑旋转,我想知道用flask作后端怎么处理前端传来的数据,能不能教教我,大佬,Orz!