一、一般思路:
1、原问题分解为子问题
2、确定状态
3、确定一些初始状态(边界)的值
4、确定状态转移方程。
二、问题特点:
1、问题有最优子结构
2、无后效性
三、求解形式:
1、记忆递归型
2、我为人人递推型(更新原有节点的值)(要注意递推顺序)
3、人人为我递推型(用已有的求未知的)
四、优化方式
1、时间优化:记忆化
2、空间优化:滚动数组
五、设计状态技巧:
如果一个状态不够用就多加几个状态变量,细化状态
POJ - 1163 The Triangle
一、递归型写法(注意记忆化):
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <map>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 105;
int Maxsum[maxn][maxn], a[maxn][maxn], n;
int maxsum(int r, int c)
{
if (Maxsum[r][c] != -1) {
return Maxsum[r][c];
}
if (r == n) {
Maxsum[r][c] = a[r][c];
} else {
Maxsum[r][c] = max (maxsum (r + 1, c), maxsum (r + 1, c + 1)) + a[r][c];
}
return Maxsum[r][c];
}
int main()
{
scanf ("%d", &n);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <=i; j++) {
scanf ("%d", &a[i][j]);
}
}
memset (Maxsum, -1, sizeof(Maxsum));
maxsum (1, 1);
printf ("%d\n", Maxsum[1][1]);
return 0;
}
二、人人为我递推型写法
1、无空间优化:
const int maxn = 105;
int a[maxn][maxn], Maxsum[maxn][maxn], n;
int main()
{
scanf ("%d", &n);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <=i; j++) {
scanf ("%d", &a[i][j]);
}
}
for (int i = 1; i <= n; i++) {
Maxsum[n][i] = a[n][i];
}
for (int i = n - 1; i >= 1; i--) {//递归顺序:由下到上
for (int j = 1; j <= i; j++) {
Maxsum[i][j] = max (Maxsum[i + 1][j], Maxsum[i + 1][j + 1]) + a[i][j];
}
}
printf ("%d\n", Maxsum[1][1]);
}
2、滚动数组空间优化:
const int maxn = 105;
int a[maxn][maxn], Maxsum[maxn], n;
int main()
{
scanf ("%d", &n);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <=i; j++) {
scanf ("%d", &a[i][j]);
}
}
for (int i = 1; i <= n; i++) {
Maxsum[i] = a[n][i];
}
for (int i = n - 1; i >= 1; i--) {//递归顺序:由下到上
for (int j = 1; j <= i; j++) {
Maxsum[j] = max (Maxsum[j], Maxsum[j + 1]) + a[i][j];
}
}
printf ("%d\n", Maxsum[1]);
}