三要素
如果问题的最优解所包含的子问题的解也是最优的,
最优子结构 就称该问题具有最优子结构。也就是说一个问题的最
优解只取决于其子问题的最优解。
将原问题分解为若干个子问题,每个子问题的求解过程
无后效性 作为一个阶段。当前阶段的求解只与之前阶段有关,与
之后阶段无关,即某阶段的状态一旦确定,就不受这个状
态后续决策的影响。
作为一个阶段。当前阶段的求解只与之前阶段有关,与之
后阶段无关,即某阶段的状态一旦确定,就不受这个状态后
续决策的影响。求解过程中每次产生的子问题并不总是
重叠子问题 新问题,有大量子问题重复。在遇到重复子问题时,只需要
在表格中查询,无需再次求解。(该性质不是使用动态规划
解决的必要条件,但是凸显了动态规划的优势。)
简单来说就是:从初始状态出发 经过一系列的状态转移 到达目标状态。求最优值、方案数、概率(一、状态转移必须有方向,且整体不能成环;二、状态的个数需要在可接受范围内)
状态:用数字精确描述的一个局面,对应问题的值
约束
状态转移:状态———→另一状态
变化
Directed Acyclic Graph(DAG)
有向无环图 无后效性 有向无环
复杂度:
状态数量×状态转移开销
O(n2) O(n)
=0(n3)
逆推代码:
vector<vector<int>> dp(n, vector<int>(n));
for (int i = 0; i < n; i ++) {
for (int j = 0; j < i; j ++) {
if (i=0) dp[i][j]=w[i][j];
else if (j =0) dp[i][j]= dp[i - 1][j]+ w[i][j];
else if (j=i) dp[i][j] =dp[i - 1][j -1]+w[i][j];
else dp[i][j] = max(dp[i - 1][j -1], dp[i - 1][j]) +w[i][j];
}
}
cout <<* max_element(dp[n - 1].begin(), dp[n1].end()) << endl;
顺推:
vector<vector<int>> dp(n, vector<int>(n,0));
dp[0][0] = w[0] [0];
for (int i = 0; i + 1 < n; i ++) {
for (int j = 0; j < i; j ++) {
dp[i + 1][j] = max(dp[i + 1][j], dp[i][j] +w[i+ 1][j]);
dp[i + 1][j +1]=max(dp[i+1][j+1], dp[i][j]+w[i+1][j+1]);
}
}
cout <<* max_element(dp[n - 1].begin(), dp[n -1].end()) << endl;
记忆化搜索:
vector<vector<int>> dp(n, vector<int>(n,-1));
auto dfs = [&] (auto &self, int i, int j) {
auto &res = dp[i][j];
if (res != -1) return res;
if (i=0) return res = w[i][j];
if (j =0) return res = self(self, i - 1, j) + w[i][j];
if (j =i) return res = self(self, i - 1, j - 1) + w[i][j];
return res = max(self(self, i - 1, j -1), self(self, i -1, j)) + w[i][j];
};
int ans = 0;
for (int j = 0; j < n; j ++) {
ans = max(ans, dfs(dfs, n -1, j));
}
cout << ans << endl;
拓补搜索:
vector<vector<int>> in_degree(n, vector<int>(n, 0));
for (int i = 0; i + 1 < n; i ++) {
for (int j = 0; j < i; j ++) {
in_degree[i + 1][j] ++;
in_degree[i +1][j + 1] ++;
}
}
vector<vector<int>> dp(n, vector<int>(n,0));
queue<pair<int, int>> q;
for (int i = 0; i < n; i ++) {
for (int j = 0; j < i; j ++) {
if (in_degree[i][j] = 0) {
q.emplace(i, j);
dp[i][j]= w[i][j];
}
}
}
pair<int, int> dirs[2] = {{1, 0}, {1, 1}};
while (!q.empty()) {
auto [i, j] = q.front();
q.pop();
for (auto [dx, dy]: dirs) {
int x = i + dx, y = j + dy;
if (x = n) continue;
dp[x][y]=max(dp[x][y],dp[i][j] +w[x][y]);
in_degree[x] [y]
if (in_degree[x][y]=0)q.emplace(x,y);
}
}
cout <<* max element(dp[n -1].begin(), dp[n-1].end()) << endl;
971

被折叠的 条评论
为什么被折叠?



