题目
有N件物品和一个容量为V的背包。第i件物品的重量是c[i],价值是v[i]。求解将哪些物品装入背包可使价值总和最大。
0 1即简单的 要 /不要 这个商品
公式:k代表第几个商品 c代表背包剩余承重
解释:
1.如果第k件太重,那就不装他,价值还是上一件的价值
2.如果没有超重,那就比较:(1)要这件商品(上一次没有要这件商品且背包剩余承重正好等于这第k件商品的重量时的价值加上第k件的价值)(2)不要这件商品(价值还是上一件的价值)
现在有5个商品,背包容量为6
序号 | 商品大小 | 商品价值 |
---|---|---|
0 | 1 | 2 |
1 | 2 | 4 |
2 | 3 | 4 |
3 | 4 | 5 |
4 | 5 | 6 |
输入
5 6
1 2
2 4
3 4
4 5
5 6
输出
10
用二维数组
套公式+看注释
#include<stdio.h>
#include<stdlib.h>
int n,V; //n代表n件商品 V代表背包承重
double **B;
int *w; //每个物品重量
double *v; //每个物品价值
void Knapsack()
{
//创建数据
scanf("%d%d",&n,&V);
int i,j;
B=(double **)malloc((n+1)*sizeof(double*));
for(i=0;i<(n+1);i++)
{
B[i]=(double *)malloc((V+1)*sizeof(double));
}
for(i=0;i<=n;i++)
{
for(j=0;j<=V;j++)
{
B[i][j]=0;
}
}
w=(int*)malloc((n+1)*sizeof(int ));
v=(double*)malloc((n+1)*sizeof(double ));
for(i=1;i<=n;i++)
{
scanf("%d%lf",&w[i],&v[i]);
}
//结束创建
//核心代码//公式
int k,c;
for(k=1;k<=n;k++)
{//k代表第几个商品 c代表背包剩余承重
//以背包为内循环,一件商品一件商品往下填价值
for(c=1;c<=V;c++)
{
if(w[k]>c)
B[k][c]=B[k-1][c];
else
{ // ↓既然背包容量已经够了 那就用当没有要他时背包里之前的容量正好差一个他的体积时的价值加上他的价值
double value_1 = B[k-1][c-w[k]]+v[k]; //要
double value_2 = B[k-1][c]; //不要
// ↑上一次背包这样容量的价值
if(value_1>value_2)
B[k][c]=value_1;
else B[k][c]=value_2;
}
}
}
}
int main()
{
Knapsack();
printf("%.0lf",B[n][V]);
return 0;
}
函数递归
从最下面一个商品开始递归
每层递归判断
1.限制1:商品是否访问完 完了则return 0;
2.限制2:判断是否大小超过背包剩余大小,超过了则判断下一个商品
3.如果都没有限制住,则进入上面一个商品的判断,并判断要这个商品与不要这个商品价值的大小
源码:
#include<stdio.h>
double B(int k,int c); //k代表第几件,W代表背包容量还剩多少 B代表价钱
double list[1010][2];
int main()
{
int n,V; //n件商品 V为背包容量
scanf("%d%d",&n,&V);
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<2;j++)
{
scanf("%lf",&list[i][j]);
}
}
double max=B(n-1,V);//最多可以得到max元
printf("%.0lf\n",max);
return 0;
}
double B(int k,int c)
{
if(k<0)
return 0;
else
{
if(list[k][0]>c)
return B(k-1,c);
else;
{
double result_1=B(k-1,c-list[k][0])+list[k][1],result_2=(B(k-1,c));//result_1为要这件商品并进行下一层递归 result_2则为不要这件商品
double result=result_1>result_2?result_1:result_2;
return result;
}
}
}
当数据过大时,运行时间会大大增加。
那么可以用数组的方法解决
测试数据
链接:https://pan.baidu.com/s/1u3tVniCGz4_lP8_9USFtgw
提取码:6666