关于背包问题动态规划代码的理解和应用——
首先,关于背包问题动态规划的详细讲解在https://v.youku.com/v_show/id_XMTQ3MzI0NzI2OA==.html这个视频链接有详细的介绍,在此引用某位大神制作的视频表示感谢,同时也说声抱歉在我的博客引用视频没有直接取得同意。关于视频中那个外国的网页也给上https://www.merlot.org/merlot/viewMaterial.htm?id=1376786
好了废话不说,直接上代码
#include<stdio.h>
#define N 6
#define M 21
int B[N][M]={0};//共5件物品,总重量是20
int w[6]={0,2,3,4,5,9};//物品重量分别是2,3,4,5,9
int v[6]={0,3,4,5,8,10};//物品价值分别是3,4,5,8,10
void knapsack(){
int k,C;//第k个商品,C表示最大容量
for(k=1;k<N;k++){
for(C=1;C<M;C++){
if(w[k]>C){
B[k][C] = B[k-1][C];
}//上面的if代码块执行当前物品的重量比背包容量大的情况
/***其实背包问题最主要的是找到在偷第n个物品时,找到存放了n-1个物品的情况,而这个if代码块就是执行这样的操作***/
else{
int value1 = B[k-1][C-w[k]]+v[k];//偷这件物品
/****注意这个是动态规划里面常用的操作方法***,C-w[k]是指偷了这个物品后容量减少w[k],偷了后价值就增加v[k]*/
int value2 = B[k-1][C];//不偷这件物品
if(value1>value2){
B[k][C] = value1;
}else{
B[k][C] = value2;
}
}
}
}
}
int main(){
knapsack();
printf("%d",B[5][20]);
}
背包问题的动态规划解法需要一个二维数组
二维数组里第一行表示无物可取的时候value=0,第一列表示背包容量为0,第二行表示能偷的物品只有一件(value=3,weight=2的那件),第二列表示背包容量为1……以此类推
关于背包问题的详细说明视频里有解说这里就不再多说了,接下来说一下这种动态规划的应用问题——
最小邮票数(题目来源是牛客网)
-
题目描述
有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。 如,有1分,3分,3分,3分,4分五张邮票,要求凑成10分,则使用3张邮票:3分、3分、4分即可。
-
输入描述:
有多组数据,对于每组数据,首先是要求凑成的邮票总值M,M<100。然后是一个数N,N〈20,表示有N张邮票。接下来是N个正整数,分别表示这N张邮票的面值,且以升序排列。
-
输出描述:
对于每组数据,能够凑成总值M的最少邮票张数。若无解,输出0。
-
示例1
输入
10
5
1 3 3 3 4
输出
3
解法说明:本题跟背包问题很相似,也是用动态规划去做,建立一个列数为11,行数为5的二维数组,上代码:
#include<stdio.h>
#define Max 100000
void bubble(int stamp[],int N){//用来进行冒泡排序的
int i,j;
int temp;
for(i=0;i<N;++i){
for(j=0;j<N-i+1;++j){
if(stamp[j]<stamp[j+1]){
temp=stamp[j];
stamp[j]=stamp[j+1];
stamp[j+1]=temp;
}
}
}
}
int main(){
int N,M,i,j;//N是邮票数量,M是需要的总额
int stamp[20];//存储邮票值的数组
int dp[20][100];//动态规划的二维数组
while(scanf("%d",&M)!=EOF){
for(scanf("%d",&N),i=0;i<N;++i){
scanf("%d",&stamp[i]);
}
bubble(stamp,N);
/*上面是负责输入的操作,和对输入的数组进行排序*/
for(i=0;i<N;++i){
dp[i][0] = 0;//面值为0时直接是0,表格第【0】列全是0
}
for(j=0;j<=M;++j){
if(j==stamp[0]){
dp[0][j]=1;//面值只有1的时候,邮票只需要一张,也就是表格里面的第【1】列全是1
}else{
dp[0][j]=Max;
}
}
/*上面是初始化操作的*/
for(i=1;i<N;++i){
for(j=1;j<=M;++j){
dp[i][j]=dp[i-1][j];
//这个if里面的就是动态规划最经典的操作
if(j>=stamp[i]&&dp[i][j]>dp[i-1][j-stamp[i]]+1){
dp[i][j]=dp[i-1][j-stamp[i]]+1;
}
}
}
printf("%d",dp[N-1][M]<Max?dp[N-1][M]:0);
}
}
进行初始化操作后的表格——
最后的表格是——