Dp
* * *
/ / \
* * * * * *
\ \ /
* * * * * * * * *
/ \
* * * * * * * *
经观察得n为偶数时,最后一层落在的点一定在n/2或n/2+1,而n为奇数时,最后一层落在的点一定在n/2+1
f[i][j]表示所有从头开始往下走到第i层第j个的路径的最大值
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 110;
int n;
int f[N][N];
int triangle[N][N];
int main()
{
scanf("%d",&n);
for(int i = 1; i<=n; i++)
for(int j = 1; j <=i; j++)
scanf("%d",&triangle[i][j]);
for(int i = 1; i<= n; i++)
for(int j = 1; j <=i; j++)
f[i][j] = max(f[i-1][j],f[i-1][j-1]) + triangle[i][j];
if(n % 2 == 0) printf("%d\n", max(f[n][n/2],f[n][n/2+1]));
else printf("%d\n", f[n][n/2+1]);
return 0;
}
dfs+剪枝
超时,过样例5/10,n=50时就不行了
#include<iostream>
using namespace std;
const int N = 1e6+10;
//三角形的坐标 (i+1)i/2+j (j<=i)
int n;
int triangle[N];
int maxN;
int maxlevel[N];
void dfs(int x, int y, int cnt, int step)
{
cnt += triangle[(x+1)*x/2+y];
if(x == n )
{
if( abs(step)<=1 ) maxN = max(maxN,cnt);
return ;
}
//剪枝
if(abs(step)>n-x) return ; // 再走也无法改变左右步数超过1的事实
int temp = cnt;
temp += maxlevel[n-1]-maxlevel[x]; //加上下面每层的最大数也无法超过maxN
if(temp <= maxN) return;
if(x == n-1){
dfs(x+1,y,cnt,step);
dfs(x+1,y+1,cnt,step);
}
else
{
dfs(x+1,y,cnt,step-1);
dfs(x+1,y+1,cnt,step+1);
}
}
int main()
{
scanf("%d",&n);
for(int i = 0; i<n; i++)
{
int temp = 0;
for(int j = 0; j <=i; j++)
{
scanf("%d",&triangle[(i+1)*i/2+j]);
temp = max(temp,triangle[(i+1)*i/2+j]);
}
maxlevel[i] = maxlevel[i-1]+temp;
}
dfs(0,0,0,0);
printf("%d",maxN);
}
佬佬第一种方法太强了,orz
DP过程为啥triangle[i][j] 加在括号外面呢?纯新手 , 求解
当你走到这一层当前位置的时候你要考虑怎么从上一层取值才能最大化,所以前面有个max上一层值,然后由于走到当前位置,所以要加上一个当前位置的值
不是很懂, 这种方式算路径最大值当然可以, 但是怎么保证路径最大值的路径是可行的, 到n/2或n/2+1的路径有很多, 怎么保证最大值路径就是满足条件的路径
在这个二分之n的路径上,这个路径左右一定合法,否则不可能回到这条路
要是实在不理解的话,可以用过数组记录走到每一个数字时向左向右的次数,最后判断一下就行了
真聪明 给你的大大的赞赞赞!
厉害 第一个方法真巧妙
厉害呀!