Welcome!
动态规划一般来说分为线性的和多维的。
此类动态规划的关键点是找到“局部最优”,一般是用best[i]代表i之后的局部最优解情况,然后用f(i)自顶向下遍历。
用flag[i]表示是否计算过,若计算过,f(i)直接返回结果(剪枝),若没计算过,则进行计算。
此通用方法思维难度较低,但在绝大部分情况下,时间复杂度都较高,因为其实质是dfs遍历的剪枝,而真正的动态规划解法是wfs的剪枝。
若时间要求不严格,则可以过,但大多数情况下还是过不了的。
典型例题:http://www.luogu.org/problem/show?pid=1280
代码:
#include <iostream>
#include <vector>
using namespace std;
int N, K;
typedef struct Task{
int p, t;
Task(int p, int t) :p(p), t(t){};
};
int min(int a, int b){ return a < b ? a : b; }
vector<Task*> tasks;
vector<int> start;
vector<int> best;
vector<bool> is;
int f(int t)
{
if (t > N) return 0;
else if (is[t]) return best[t];
else if (start[t] == -1) return f(t + 1);
else
{
int mint = 0x7fffffff;
for (int i = start[t]; i < K && tasks[i]->p == t; i++)
mint = min(mint, f(t + tasks[i]->t) + tasks[i]->t);
best[t] = mint;
is[t] = true;
return mint;
}
}
int main()
{
freopen("t.txt", "r", stdin);
cin >> N >> K;
start.resize(N + 1, -1);
best.resize(N + 1, 0);
is.resize(N + 1, false);
for (int i = 0; i < K; i++)
{
int p, t;
cin >> p >> t;
tasks.push_back(new Task(p, t));
if (start[p] == -1)
start[p] = i;
}
cout << N - f(1);
return 0;
}
01背包,完全背包,最大上升子序列等等。