原题链接
题目大意
给你一个 n n n行的数字三角形,数字三角形的格式如下:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
对于每一个数,你可以走到在他下面的两个数。
求出从顶部开始走到底部经过数字的最大总和。
S
a
m
p
l
e
\mathbf{Sample}
Sample
I
n
p
u
t
\mathbf{Input}
Input
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output
30
H
i
n
t
&
E
x
p
l
a
i
n
\mathbf{Hint\&Explain}
Hint&Explain
路径为7-3-8-7-5
,总和为30
。
解题思路
本题可以用两种方法,顺推和逆推
①顺推
顾名思义,顺推就是从三角形的最顶上开始推,一直推到最后一行。
d
p
dp
dp转移方程如下:
设
f
i
,
j
f_{i,j}
fi,j为从第
1
1
1行第
1
1
1列推到第
i
i
i行第
j
j
j列的最大值,
a
i
,
j
a_{i,j}
ai,j为三角形第
i
i
i行第
j
j
j列的数字
f
i
,
j
=
{
a
i
,
j
i
=
1
f
i
−
1
,
j
+
a
i
,
j
j
=
1
m
a
x
(
f
i
−
1
,
j
,
f
i
−
1
,
j
−
1
)
+
a
i
,
j
1
<
i
≤
n
,
1
<
j
≤
n
f_{i,j}=\begin{cases} a_{i,j}&i=1 \\f_{i-1,j}+a_{i,j}&j=1 \\max(f_{i-1,j}\ ,\ f_{i-1,j-1})+a_{i,j}& 1<i\le n,1<j\le n \end{cases}
fi,j=⎩⎪⎨⎪⎧ai,jfi−1,j+ai,jmax(fi−1,j , fi−1,j−1)+ai,ji=1j=11<i≤n,1<j≤n
而答案就是
max
1
≤
i
≤
n
{
f
n
,
i
}
\max_{1\le i\le n}\{f_{n,i}\}
1≤i≤nmax{fn,i}
解题思路写了,代码随即而来:
#include<iostream>
using namespace std;
int n;
int a[1001][1001];
int f[1001][1001];
int main()
{
cin>>n;
for(int i=1; i<=n; i++)
for(int j=1; j<=i; j++)
{
cin>>a[i][j];
}
f[1][1]=a[1][1];
int res=0;
for(int i=2; i<=n; i++)
{
for(int j=1; j<=i; j++)
{
f[i][j]=max(f[i-1][j],f[i-1][j-1])+a[i][j];
if(i==n) res=max(res,f[i][j]);
}
}
cout<<res;
return 0;
}
②逆推
就是顺推反过来,从第
n
n
n行推到第一行。
d
p
dp
dp转移方程如下:
设
f
i
,
j
f_{i,j}
fi,j为从第
n
n
n行 (没有列) 推到第
i
i
i行第
j
j
j列的最大值,
a
i
,
j
a_{i,j}
ai,j为三角形第
i
i
i行第
j
j
j列的数字
f
i
,
j
=
{
a
i
,
j
i
=
n
f
i
−
1
,
j
+
a
i
,
j
j
=
1
f
i
−
1
,
j
+
f
i
−
1
,
j
−
1
+
a
i
,
j
1
≤
i
<
n
,
1
<
j
≤
n
f_{i,j}=\begin{cases} a_{i,j}&i=n \\f_{i-1,j}+a_{i,j}&j=1 \\f_{i-1,j}+f_{i-1,j-1}+a_{i,j}&1\le i<n,1<j\le n \end{cases}
fi,j=⎩⎪⎨⎪⎧ai,jfi−1,j+ai,jfi−1,j+fi−1,j−1+ai,ji=nj=11≤i<n,1<j≤n
而答案就是
f
1
,
1
f_{1,1}
f1,1
代码在下面
∼
\sim
∼
相比之下,逆推比较好,因为他的答案就是 f 1 , 1 f_{1,1} f1,1,而顺推则还要加一个 f o r for for来判断答案,虽然也不是太难,但能方便一点就方便一点吧。
上代码
此为逆推代码
#include<iostream>
using namespace std;
int n;
int a[1001][1001];
int f[1001][1001];
int main()
{
freopen("xxx.in","r",stdin);
freopen("xxx.out","w",stdout);
cin>>n;
for(int i=1; i<=n; i++)
for(int j=1; j<=i; j++)
{
cin>>a[i][j];
if(i==n) f[i][j]=a[i][j];
}
for(int i=n-1; i>=1; i--)
{
for(int j=1; j<=i; j++)
{
f[i][j]=max(f[i+1][j],f[i+1][j+1])+a[i][j];
}
}
cout<<f[1][1];
fclose(stdin);
fclose(stdout);
return 0;
}
完美切题 ∼ \sim ∼