动态规划(DP)

三要素

                          如果问题的最优解所包含的子问题的解也是最优的,

最优子结构        就称该问题具有最优子结构。也就是说一个问题的最

                          优解只取决于其子问题的最优解。

                 将原问题分解为若干个子问题,每个子问题的求解过程

无后效性  作为一个阶段。当前阶段的求解只与之前阶段有关,与

                 之后阶段无关,即某阶段的状态一旦确定,就不受这个状

                 态后续决策的影响。

                        作为一个阶段。当前阶段的求解只与之前阶段有关,与之

                        后阶段无关,即某阶段的状态一旦确定,就不受这个状态后

                        续决策的影响。求解过程中每次产生的子问题并不总是

重叠子问题      新问题,有大量子问题重复。在遇到重复子问题时,只需要

                        在表格中查询,无需再次求解。(该性质不是使用动态规划

                        解决的必要条件,但是凸显了动态规划的优势。)

简单来说就是:从初始状态出发 经过一系列的状态转移 到达目标状态。求最优值、方案数、概率(一、状态转移必须有方向,且整体不能成环;二、状态的个数需要在可接受范围内)

状态:用数字精确描述的一个局面,对应问题的值

                            约束

状态转移:状态———→另一状态

                            变化

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;
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值