做动态规划的题目之前养成手写dp的习惯,会避免很多问题
小明的背包(01背包)
https://www.lanqiao.cn/problems/1174/learning/?page=1&first_category_id=1&sort=students_count&problem_id=1174
- 解释:一定要自己动手写一下dp,然后看一下怎么初始化的,然后再开始动手写代码,包括一维数组的实现为什么要倒叙j,因为会被覆盖掉
- 二维数组代码:
#include <iostream>
using namespace std;
int W[101];
int V[101];
int dp[101][1001];
int N, C;
int main()
{
// 请在此输入您的代码
cin >> N >> C;
for(int i = 0; i < N; i++) {
cin >> W[i] >> V[i];
}
//初始化:
//初始化列:
for(int i = 0; i < N ;i++) {
dp[i][0] = 0;
}
//初始化行:
for(int i = 0; i <= C; i++) {
if(W[0] <= i) {
dp[0][i] = V[0];
}else{
dp[0][i] = 0;
}
}
for(int i = 1; i < N; i++) {
for(int j = 1; j <= C; j++) {
if(W[i] > j) {
dp[i][j] = dp[i - 1][j];
}else {
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - W[i]] + V[i]);
}
}
}
cout << dp[N - 1][C];
return 0;
}
- 一维数组代码:
#include<iostream>
#include<string.h>
using namespace std;
int N, C;
int W[101];
int V[101];
int dp[1001];
int main() {
cin >> N >> C;
memset(dp, 0, sizeof(dp));
for(int i = 0; i < N; i++) {
cin >> W[i] >> V[i];
}
for(int i = 0; i < N; i++) {
// for(int j = 1; j <= C; j++) {
// //这里为什么不能从小到大循环呢?
// if(W[i] <= j) {
// dp[j] = max(dp[j], dp[j - W[i]] + V[i]);
// //..............如果从小到大,那么大的j - W[i]其实不是i - 1的时候的状态,而是被覆盖掉了
// }
// }
for(int j = C; j >= W[i]; j--) {
dp[j] = max(dp[j], dp[j - W[i]] + V[i]);
}
}
cout << dp[C];
return 0;
}
小明的背包2(完全背包)
https://www.lanqiao.cn/problems/1175/learning/?page=1&first_category_id=1&sort=students_count&name=小明的背包2
- 解释: 还是一样的自己动手写一下dp表之后再做判断,先看二维的是怎么判断的
- 二维数组代码:
#include <iostream>
using namespace std;
int w[1001];
int v[1001];
int dp[1001][1001];
int n, c;
int main()
{
// 请在此输入您的代码
cin >> n >> c;
for(int i = 0; i < n; i++) {
cin >> w[i] >> v[i];
}
//初始化第一列:
for(int i = 0; i < n; i++) {
dp[i][0] = 0;
}
//初始化第一行:
for(int i = 0; i <= c; i++) {
if(i >= w[0]) {
dp[0][i] = i/w[0] * v[0];
}else{
dp[0][i] = 0;
}
}
for(int i = 1; i < n; i++) {
for(int j = 0; j <= c; j++) {
if(w[i] > j) {
dp[i][j] = dp[i - 1][j];
}else {
//到这里又要分两种情况,加还是不加,如果不加的话那就是dp[i - 1][j],也包含在下面的情况中;
for(int k = 0; k * w[i] <= j; k++){
dp[i][j] = max(dp[i][j], dp[i - 1][j - k*w[i]] + k*v[i]);
}
}
}
}
cout << dp[n - 1][c];
return 0;
}
- 解释:一旦变成顺序的话就会导致每一个物品多加,所以可以加以区别
- 一维代码:
#include<iostream>
#include<string.h>
using namespace std;
int w[1001];
int v[1001];
int dp[1001];
int n, c;
//你只要记住背包大小顺序的话就会导致多加就行了,那么完全背包就是顺序的
int main() {
cin >> n >> c;
memset(dp, 0, sizeof(dp));
for(int i = 0; i < n; i++) {
cin >> w[i] >> v[i];
}
for(int i = 0; i < n; i++) {
for(int j = 0; j <= c; j++) {
if(w[i] <= j)
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
}
}
cout << dp[c];
return 0;
}
2022
https://www.lanqiao.cn/problems/2186/learning/?page=1&first_category_id=1&sort=students_count&name=2022
数字三角形
https://www.lanqiao.cn/problems/505/learning/?page=1&first_category_id=1&sort=students_count&name=数字三角形
- 代码
#include<bits/stdc++.h>
using namespace std;
int n;
int nums[101][101];
int dp[101][101];
int main()
{
cin >> n;
for(int i = 0; i < n; i++) {
for(int j = 0; j < i + 1; j++) {
cin >> nums[i][j];
}
}
//初始化:
dp[0][0] = nums[0][0];
for(int i = 1; i < n; i++) {
for(int j = 0; j < i + 1; j++) {
//注意还要判断边界条件
dp[i][j] = nums[i][j] + max((j - 1 >= 0 ? dp[i - 1][j - 1] : 0), (j <= i - 1 ? dp[i - 1][j] : 0));
}
}
if(n%2 == 0) {
cout << max(dp[n - 1][(n - 1)/2], dp[n - 1][(n - 1)/2 + 1]);
}else {
cout << dp[n - 1][n/2];
}
return 0;
}