#include<stdio.h>
#include<stdlib.h>
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
#define N 100
int a[N]={0};
int temp[N]={0};
int dp[N][N]={0};
int m[N][N]={0};
//0-1背包问题
// int n=5,c=10;
// int w[]={2,2,6,5,4};
// int v[]={6,3,5,4,6};
//穷举法 时间复杂度T(n)=O(2^n)
//每个物品选或者不选一共2^n种情况
void BagProblem1(int len,int *w,int *v,int capacity)
{
int i,j,k;
int maxValue;
int Value;
int Weight;
int flag=0;
int num=1<<len;
for(i=0;i<num;i++)
{
j=i;
k=0;
Value=0;
Weight=0;
flag=0;
while(j)
{
if(j&1)
{
a[k]=1;
Value+=v[k];
Weight+=w[k];
}
j>>=1;
k++;
}
if(Weight<=capacity && Value>maxValue)
{
maxValue=Value;
flag=1;
}
if(flag==1)
{
for(int q=0;q<len;q++)
{
temp[q]=a[q];
}
}
for(int q=0;q<len;q++)
{
a[q]=0;
}
}
for(int q=0;q<len;q++)
{
printf("%d ",temp[q]);
}
printf("\n");
printf("%d\n",maxValue);
}
//公式法 时间复杂度T(n)=O(n^2)
//定义dp[i][j]表示在第1~i个物品(前i个物品)中选择满足背包容量的最大收益
//当第i个物品重量大于背包容量时,dp[i][j]=dp[i-1][j]
//当第i个物品重量小于背包容量时,可选放或者不放
//dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])
void BagProblem2(int n,int *w,int *v,int capacity)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<=capacity;j++)
{
dp[i][j]=dp[i-1][j];
if(j>=w[i])
{
dp[i][j]=max(dp[i][j],dp[i-1][j-w[i]]+v[i]);
}
}
}
printf("%d\n",dp[n-1][capacity]);
}
int main()
{
int n,c;
scanf("%d %d",&n,&c);
int w[n];
int v[n];
for(int i=0;i<n;i++)
{
scanf("%d",&w[i]);
}
for(int i=0;i<n;i++)
{
scanf("%d",&v[i]);
}
// BagProblem1(n,w,v,c);
BagProblem2(n,w,v,c);
}
动态规划求解0-1背包问题
表的填写顺序为从下往上从左往右,m(i,j)表示从第i~n个物品中选择满足容量j的最大收益。i=5时,j<4时,装不下第5个物品,效益m(i,j)为0,当j>=4时,装得下,效益m(i,j)为v[5]=6;i=4时,当j<=w[i]=4时,m(i,j)=m(i+1,j),当j>=5时,m(i,j)=max(m(i+1,j),m(i+1,j-w[i])+v[i]),m(4,5)=max(6,0+4)=6
倒退法输出放入的物品
#include<stdio.h>
#include<stdlib.h>
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
#define N 100
int m[N][N]={0};
int a[N]={0};
//0-1背包问题
//动态规划 时间复杂度T(n)=O(nc) 空间复杂度S(n)=O(nc)
//m[i][j]表示当前物品是i,从第i~n个物品中选择满足容积的最大效益
//当第i个物品重量大于容积0<=j<wi时,m[i][j]=m[i+1][j]
//当第i个物品重量小于容积j>wi时,m[i][j]=max(m[i+1][j],m[i+1][j-wi]+vi)
//m[n][j]表示把第n个物品放入容积为j的背包中的最大效益
void BagProblem3(int n,int *w,int *v,int capacity)
{
int jMax=min(w[n]-1,capacity);//避免w[n]>>capacity时数组越界
//对第n行进行赋值操作
for(int j=0;j<=jMax;j++)
{
m[n][j]=0;
}
for(int j=w[n];j<=capacity;j++)
{
m[n][j]=v[n];
}
//从第n-1行到第一行进行赋值
for(int i=n-1;i>=1;i--)
{
int jMax=min(w[i]-1,capacity);
for(int j=0;j<=jMax;j++)
{
m[i][j]=m[i+1][j];
}
for(int j=w[i];j<=capacity;j++)
{
m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
}
}
//返回第一行第capacity列的值为最优值,表示从第1个到第n个物品中选择满足背包容量的最大效益
printf("%d\n",m[1][capacity]);
}
//使用倒推法求出每个物品是否被选中
//从右上角回退,if(m[i][j]=m[i+1][j])表示没有选中
//if(m[i][j]!=m[i+1][j])表示选中,则看m[i+1][j-w[i]]处的值继续判断
void Traceback(int n,int *w,int *v,int capacity)
{
for(int i=1;i<n;i++)
{
if(m[i][capacity]==m[i+1][capacity])
{
a[i]=0;
}
else
{
a[i]=1;
capacity=capacity-w[i];
}
}
a[n]=(m[n][capacity]>0?1:0);//最后一行如果值为0表示没放入,非0表示放入
for(int i=1;i<=n;i++)
{
printf("%d ",a[i]);
}
}
int main()
{
int n,c;
scanf("%d %d",&n,&c);
int w[n+1];
int v[n+1];
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&v[i]);
}
BagProblem3(n,w,v,c);
Traceback(n,w,v,c);
}
回溯法求解0-1背包问题
#include<stdio.h>
#include<stdlib.h>
#define N 100
int w[N];
int v[N];
int A[N]={0};
int visited[N]={0};
int n,c;
int maxValue=-1;
int value;
// int n=5,c=10;
// int w[]={2,2,6,5,4};
// int v[]={6,3,5,4,6};
void solve(int dep)
{
if(dep==n)
{
if(value>maxValue)
{
maxValue=value;
for(int j=0;j<n;j++)
{
A[j]=visited[j];
}
}
}
else
{
//搜索左枝(物品装不进时剪掉左枝) 约束函数
if(w[dep]<=c)
{
c-=w[dep];value+=v[dep];visited[dep]=1;
solve(dep+1);//继续向下深度搜索
c+=w[dep];value-=v[dep];visited[dep]=0;//回退
}
//搜索右枝 限界函数
visited[dep]=0;
solve(dep+1);
}
}
int main()
{
scanf("%d %d",&n,&c);
for(int i=0;i<n;i++)
{
scanf("%d",&w[i]);
}
for(int i=0;i<n;i++)
{
scanf("%d",&v[i]);
}
solve(0);
printf("%d\n",maxValue);
for(int i=0;i<n;i++)
{
printf("%d ",A[i]);
}
printf("\n");
}