动态规划的核心感觉像是状态转移,某一个状态依赖于前面的几个状态。
通过递推关系来完成
. - 力扣(LeetCode)[509. 斐波那契数]
. - 力扣(LeetCode) 70.爬楼梯
[746. 使用最小花费爬楼梯]. - 力扣(LeetCode)
[62. 不同路径]. - 力扣(LeetCode)
[63. 不同路径||] . - 力扣(LeetCode)
96.不同的二叉搜索树 . - 力扣(LeetCode)
0-1背包
一开始我用性价比来排序,也就是价值/重量,时间反而更快一点
//16:01
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
bool cmp(vector<double> a,vector<double> b){
if(abs(a[2]-b[2])<=0.001)return a[0]>b[0];
else return a[2]>b[2];
}
int main(){
int M,N;
cin>>M>>N;
vector<vector<double>> bag(M,vector<double>(3,0));
int cur=0;
for(int i=0;i<M;i++){
cin>>cur;
bag[i][0]=cur;
}
for(int i=0;i<M;i++){
cin>>cur;
bag[i][1]=cur;
}
for(int i=0;i<M;i++){
if(bag[i][1]==0)bag[i][2]=0;
else if(bag[i][0]==0)bag[i][2]=1000;
else {bag[i][2]=bag[i][1]/bag[i][0];}
}
sort(bag.begin(),bag.end(),cmp);
int val=0;
for(int i=0;i<M;i++){
if(N>=bag[i][0]){
val+=bag[i][1];
N-=bag[i][0];
}
}
cout<<val;
return 0;
}
dp【i】【j】 表示背包容量为 j 时,从 0..i 类物品种选取,可以获得的最大价值。
dp的代码怎么会这么复杂呢,感觉一点都不方便
//二维dp数组实现
// #include <bits/stdc++.h>
#include<iostream>
#include<vector>
using namespace std;
int main() {
int M,MAXWeight;
cin>>M>>MAXWeight;
vector<int> weight(M);//每种材料所占空间
vector<int> value(M);//每种材料的价值
//这个是关键,dp[i][j]代表当最大空间为j时,可以从0-(i-1)个物品中获得的最大价值是多少
vector<vector<int>> dp(M,vector<int>(MAXWeight+1,0));
int cur=0;
for(int i=0;i<M;i++){
cin>>cur;
weight[i]=cur;
}
for(int i=0;i<M;i++){
cin>>cur;
value[i]=cur;
}
//先初始化dp[0],假设只取第0个材料,它的重量就是weight[0]
//也就是说,当空间小于weight[0]时价值为0,[定义的时候已初始化]
//而当空间大于等于weight[0]时,说明可以取到这个材料了,所以都设为value[0]
for(int j=weight[0];j<=MAXWeight;j++){
dp[0][j]=value[0];
}
for(int i=1;i<M;i++){//循环遍历每一个材料
for(int j=0;j<=MAXWeight;j++){//填充每一个空间下可以得到的最大价值}
if(j<weight[i])
dp[i][j]=dp[i-1][j];//如果当前材料的重量直接大于最大空间,那么取上一层的dp
else{
//核心代码,将此材料加入dp如果能使value加大,那么就替换
//放进去物品i和不放进去物品i取最大值
dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
}
}
}
cout<<dp[M-1][MAXWeight];
return 0;
}
这里的第二层for循环也可以倒序
因为一反正用的都是上一层的数据,
而如果换成一维dp,那就必须倒序了,因为你是随时覆盖的,dp[][]用的是左上角的数据,如果dp[]正序,将会导致某个数被多次计算,【因为有个这个,dp[i-1][j-weight[i]]会用到前面的数据】
所以只能倒序
还有一些细节方面的修改
//一维dp数组实现
// #include <bits/stdc++.h>
#include<iostream>
#include<vector>
using namespace std;
int main() {
int M,MAXWeight;
cin>>M>>MAXWeight;
vector<int> weight(M);//每种材料所占空间
vector<int> value(M);//每种材料的价值
//这个是关键,dp[i][j]代表当最大空间为j时,可以从0-(i-1)个物品中获得的最大价值是多少
vector<int> dp(MAXWeight+1,0);
int cur=0;
for(int i=0;i<M;i++){
cin>>cur;
weight[i]=cur;
}
for(int i=0;i<M;i++){
cin>>cur;
value[i]=cur;
}
for(int i=0;i<M;i++){//循环遍历每一个材料
for(int j=MAXWeight;j>=0;j--){//填充每一个空间下可以得到的最大价值}
if(j>=weight[i]) {
//核心代码,将此材料加入dp如果能使value加大,那么就替换
dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
}
}
}
cout<<dp[MAXWeight];
return 0;
}
寄
原来dp的实际应用这么难!!!
这题根本想不到啊
[416. 分割等和子集]
[1049. 最后一块石头的重量 II]
494.目标和
474.一和零
class Solution {
public:
int change(int amount, vector<int>& coins) {
int len=coins.size();
vector<int> dp(amount+1,0);
int coin=0;
//赋初始值
dp[0]=1;
for(int i=0;i<len;i++){//遍历coins里的每一个coin
coin=coins[i];
for(int j=coin;j<=amount;j++){//因为是完全背包,所以从左往右遍历
dp[j]=dp[j]+dp[j-coin];//好奇怪啊,不理解
}
}
return dp[amount];
}
};