数塔dp。
和那种网格dp差不多,也可以有四种做法,不过数塔的终点有n
个,如果要让dp[i][j]
表示起点到当前点的子问题,最后还要枚举。
所以这道题就让dp[i][j]
表示当前点(第i
行第j
个)到终点(最后一行)的子问题的最优解。然后就有两种写法,递推的话只用一个数组就够了(因为访问的之前状态一定已经被计算过了),而递归的话需要一个标记(以判断这个子问题是否被计算过),所以要用两个数组。
递推:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <queue>
using namespace std;
int dp[101][101];
int N, T;
void init() {}
int main()
{
scanf("%d", &T);
for (; T--;)
{
scanf("%d", &N);
init();
for (int i = 1; i <= N; i++)
for (int j = 1; j <= i; j++)
scanf("%d", &dp[i][j]);
for (int i = N - 1; i >= 1; i--)
for (int j = 1; j <= i; j++)
dp[i][j] += max(dp[i + 1][j], dp[i + 1][j + 1]);
printf("%d\n", dp[1][1]);
}
return 0;
}
递归:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <queue>
using namespace std;
const int INF = 1e9;
int a[101][101];
int dp[101][101];
int N, T;
void init()
{
for (int i = 1; i <= N; i++)
for (int j = 1; j <= i; j++)
dp[i][j] = -INF;
}
int dfs(int i, int j)
{
if (i == N) return a[i][j];
if (dp[i][j] != -INF) return dp[i][j];
int t = max(dfs(i + 1, j), dfs(i + 1, j + 1));
return dp[i][j] = t + a[i][j];
}
int main()
{
scanf("%d", &T);
for (; T--;)
{
scanf("%d", &N);
init();
for (int i = 1; i <= N; i++)
for (int j = 1; j <= i; j++)
scanf("%d", &a[i][j]);
printf("%d\n", dfs(1, 1));
}
return 0;
}