题意已经很清楚了,不再赘述。
解题思路
先不考虑乘三倍的情况。
将金字塔中每一个数看作一个点。
我们用
�
�
�
,
�
dp
i,j
来表示走到第
�
i 行第
�
j 个点时走过的最大得分。
因为点(
�
,
�
i,j)是从点(
�
−
1
,
�
i−1,j)和点(
�
−
1
,
�
−
1
i−1,j−1)走来,所以易得状态转移方程式:
�
�
�
,
�
=
max
(
�
�
�
−
1
,
�
,
�
�
�
−
1
,
�
−
1
)
+
�
�
,
�
dp
i,j
=max(dp
i−1,j
,dp
i−1,j−1
)+a
i,j
然后考虑乘三倍的情况。
用
�
�
�
,
�
,
�
dp
i,j,l
来表示走到第
�
i 行第
�
j 个点,乘
�
l 次三倍时走过的最大得分。 结合不考虑乘三倍情况的状态转移方程式,易得最终状态转移方程式:
�
�
�
,
�
,
�
=
{
�
�
�
,
�
,
�
=
max
(
�
�
�
−
1
,
�
,
�
,
�
�
�
−
1
,
�
−
1
,
�
)
+
�
�
,
�
,
(
�
=
0
)
�
�
�
,
�
,
�
=
max
(
�
�
�
,
�
,
�
,
�
�
�
−
1
,
�
,
�
−
1
+
�
�
,
�
×
3
,
�
�
�
−
1
,
�
−
1
,
�
−
1
+
�
�
,
�
×
3
)
,
Otherwise.
dp
i,j,l
={
dp
i,j,l
=max(dp
i−1,j,l
,dp
i−1,j−1,l
)+a
i,j
,(l=0)
dp
i,j,l
=max(dp
i,j,l
,dp
i−1,j,l−1
+a
i,j
×3,dp
i−1,j−1,l−1
+a
i,j
×3),Otherwise.
以上是代码核心部分。 在搜索时要记得套两层循环(
�
j 和
�
k),应为存在负数,所以不是乘三倍的次数越多越好。
k = min(k, n); // 不然可能导致没搜到k次,值为-3e9的情况。
for(int j = 1; j <= n; ++ j)
for(int l = 0; l <= k; ++ l)
maxm = max(maxm, dp[n][j][l]);
cout << maxm;
最后要记得在开始时把数组初始化。
AC 代码
#include
using namespace std;
typedef long long ll;
const int N = 105;
int n, k;
ll a[N][N], dp[N][N][5505], maxm = -3e9;
signed main()
{
//输入
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> k;
//初始化
for(int i = 1; i <= n; ++ i)
for(int j = 0; j <= n; ++ j)
for(int l = 0; l <= k; ++ l)
dp[i][j][l] = -3e9; //a[i][j]最小是-1e9,还要乘3,所以设为-3e9(记得开long long)。
//边输入边做dp
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= i; ++ j)
{
cin >> a[i][j];
for(int l = 0; l <= k && l <= i; ++ l)
{
if(l == 0)
dp[i][j][l] = max(dp[i - 1][j][l], dp[i - 1][j - 1][l]) + a[i][j];
else
{
dp[i][j][l] = max(dp[i - 1][j][l], dp[i - 1][j - 1][l]) + a[i][j];
dp[i][j][l] = max(dp[i][j][l], max(dp[i - 1][j][l - 1], dp[i - 1][j - 1][l - 1]) + a[i][j] * 3);
}
}
}
k = min(k, n); // 不然可能导致没搜到k次,值为-3e9的情况。
//搜索答案
for(int j = 1; j <= n; ++ j)
for(int l = 0; l <= k; ++ l)
maxm = max(maxm, dp[n][j][l]);
//输出
cout << maxm;
return 0;
}