问题1:装箱问题
题解:这题其实本质上也是01背包,只不过算是变式,要求剩余空间最小值,我们可以转换成最大可以装多少的问题,然后就可以很快的写出题的答案
#include<bits/stdc++.h>
using namespace std;
int v,n;
int w[50];
int dp[20005];
int main()
{scanf("%d%d",&v,&n);for(int i=0;i<n;i++){scanf("%d",&w[i]);}for(int i=0;i<n;i++){for(int j=v;j>=w[i];j--){dp[j]=max(dp[j],dp[j-w[i]]+w[i]);}}printf("%d",v-dp[v]);return 0;
}
问题2:开心的金明
题解:和第一道题一样都属于01背包只不过是一个变式,因此我们还是可以找出其中的关系式
dp[j]=max(dp[j],dp[j-v[i]]+v[i]*w[i]) (i代表第i个物品,j代表钱数为j)
#include<bits/stdc++.h>
using namespace std;
int n,w1;
int w[30];
int v[30];
int dp[30005];int main()
{scanf("%d%d",&w1,&n);for(int i=0;i<n;i++){scanf("%d%d",&w[i],&v[i]);}for(int i=0;i<n;i++){for(int j=w1;j>=w[i];j--){dp[j]=max(dp[j],dp[j-w[i]]+w[i]*v[i]);}}printf("%d",dp[w1]);return 0;
}
问题3:小A点菜
题解:这题也是很有意思昂,和平常的01背包终于换了个考法了,但仔细思索发现还是那样,所以难度也不是很大,但是需要找到相应的递推关系式dp[j]=dp[j]+dp[j-v[i]];
#include <bits/stdc++.h>
using namespace std;
int n,m;
int v[105];
int dp[10005];int main()
{int flag=0x3f3f3f3f;scanf("%d%d",&n,&m);for(int i=0;i<n;i++){scanf("%d",&v[i]);if(v[i]<flag)flag=v[i];}dp[0]=1;for(int i=0;i<n;i++){for(int j=m;j>=v[i];j--){dp[j]=dp[j]+dp[j-v[i]];}}printf("%d",dp[m]);return 0;
}
问题4:精卫填海
题解:典型的01背包变式,但是我们需要额外设置一个变量,用于更新最小消耗的体力
只要满足了k(要求的填平所需要的最小体积)就可以更新
#include<bits/stdc++.h>
using namespace std;
int v,n,c;
int k[10005];
int m[10005];
int dp[10005];
int main()
{scanf("%d%d%d",&v,&n,&c);for(int i=0;i<n;i++){scanf("%d%d",&k[i],&m[i]);}int sum=-1;for(int i=0;i<n;i++){for(int j=c;j>=m[i];j--){dp[j]=max(dp[j],dp[j-m[i]]+k[i]);if(dp[j]>=v){sum=max(sum,c-j);}}}if(sum==-1){printf("Impossible");}elseprintf("%d",sum);return 0;
}
问题5:Bessie's Weight Problem G
题解,很简单和第1,2题都是一个模版没啥可说的
#include<bits/stdc++.h>
using namespace std;int h,n;
int w[505];
int dp[45005];
int main()
{scanf("%d%d",&h,&n);for(int i=0;i<n;i++){scanf("%d",&w[i]);}for(int i=0;i<n;i++){for(int j=h;j>=w[i];j--){dp[j]=max(dp[j],dp[j-w[i]]+w[i]);}}printf("%d",dp[h]);return 0;
}
问题6:Hay For Sale S
题解:很简单的01背包问题,没什么过多解释,找出关系式就好
#include<bits/stdc++.h>
using namespace std;
int w,n;
int v[5005];
int dp[50005];
int main()
{scanf("%d%d",&w,&n);for(int i=0;i<n;i++){scanf("%d",&v[i]);}for(int i=0;i<n;i++){for(int j=w;j>=v[i];j--){dp[j]=max(dp[j],dp[j-v[i]]+v[i]);}}printf("%d",dp[w]);return 0;
}
总结
做这种动态规划问题,一定要有一个思路,那就是去找动规五部曲
1.明白dp数组含义
2.找到dp关系式
3.给dp数组赋初值
4.遍历顺序
5.打印数组,检查错误