今天有点颓废,控制不住想刷短视频(短视频害人啊!)就学了一点东西,刷了一个题(@_@)
今天总结了一下动态规划:
概念:
动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。
所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的
解题步骤:
现在为止任然对动态规划是一种懵逼的状态,一些简单的题对着状态转移公式写题目还没完全理解就AC了,一遇到难一点的题目就完全一点思路没有,然后看题解,然后继续照葫芦画瓢陷入这种恶性循环中。
看了一个教程上的动态规划解题步骤:
- 确定dp数组(dp table)以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
对于动态规划问题,拆解为如上五步曲,这五步都搞清楚了,才能说把动态规划真的掌握了!
动态规划的两个主要问题:
背包问题:
子序列问题:
这些问题还等待着慢慢去学习
刷题:
一个简单的01背包:
题目描述
有一个箱子容量为 VV,同时有 nn 个物品,每个物品有一个体积。
现在从 nn 个物品中,任取若干个装入箱内(也可以不取),使箱子的剩余空间最小。输出这个最小值。
输入格式
第一行共一个整数 VV,表示箱子容量。
第二行共一个整数 nn,表示物品总数。
接下来 nn 行,每行有一个正整数,表示第 ii 个物品的体积。
输出格式
共一行一个整数,表示箱子最小剩余空间。
输入输出样例
输入 #1
24
6
8
3
12
7
9
7输出 #1
0
说明/提示
对于 100%100% 数据,满足 0<n≤300<n≤30,1≤V≤200001≤V≤20000。
【题目来源】
NOIP 2001 普及组第四题
思路就不用说了,直接看代码:
//dp一维
/*
#include<bits/stdc++.h>
using namespace std;
int main(){
int v,n;
scanf("%d %d",&v,&n);
int jk[40]={0};
int dp[20012]={0};//箱子容量为i时装入物体最多的数量
for(int i=1;i<=n;i++){
scanf("%d",&jk[i]);
}
for(int i=1;i<=n;i++){//决策第n个物体
for(int k=v;k>=jk[i];k--){//箱子容量为k时
dp[k]=max(dp[k],dp[k-jk[i]]+jk[i]);//dp[k-jk[i]]:箱子在装了物体i之后剩余箱子容量能装的最大重量
}
}
printf("%d",v-dp[v]);
}
*/
//dp二维
#include<bits/stdc++.h>
using namespace std;
int dp[20012][20012] = {0}; //箱子容量为i时装入物体最多的数量
int main() {
int v, n;
scanf("%d %d", &v, &n);
int jk[40] = {0};
for (int i = 1; i <= n; i++) {
scanf("%d", &jk[i]);
}
for (int i = 1; i <= n; i++) { //决策第n个物体
for (int k = 1; k <= v; k++) { //箱子容量为k时
if (k < jk[i]) {
dp[i][k] = dp[i - 1][k]; //状态继承
} else {
dp[i][k]=max(dp[i-1][k],dp[i-1][k-jk[i]]+jk[i]);
}
}
}
printf("%d", v - dp[n][v]);
}
/*
//dfs深搜
#include<stdio.h>
int jk[40], book[40] = {0};
int v, n, max = 0, tt = 0;
void dfs() {
for (int i = 0; i < n; i++) {
if (book[i] == 0 && tt + jk[i] <= v) {
book[i] = 1;
tt += jk[i];
if (tt > max) {
max = tt;
}
dfs();
book[i] = 0;
tt -= jk[i];
}
}
}
int main() {
scanf("%d %d", &v, &n);
for (int i = 0; i < n; i++) {
scanf("%d", &jk[i]);
}
dfs();
printf("%d", v - max);
}
*/
但愿这个世界没有手机