0
点赞
收藏
分享

微信扫一扫

算法:0-1背包问题


看b站一个人讲的,虽然讲的不好,但是课件做的还是挺不错的,拿来借鉴一下(2333)

算法:0-1背包问题_递归


算法:0-1背包问题_i++_02


算法:0-1背包问题_0-1背包_03


算法:0-1背包问题_0-1背包_04


算法:0-1背包问题_递归_05


算法:0-1背包问题_递归_06

下面开始讲解:
m(i,j)是背包容量为j,可选择物品为i,i+1,…,n时0-1背包问题的最优值。

m(i+1,j)可选择物品为i+1,…,n时0-1背包问题的最优解。

m(n,j)可选择物品为n时0-1背包问题的最优值,规模已为1

易知:

算法:0-1背包问题_i++_07


递归式推导:

是否将第i件物品放入?

如果不放,背包当前产生价值仍为m(i+1,j);

如果放入,调整背包容量j-wi,背包当前产生价值为 m(i+1, j-wi ) + vi

递归式:

算法:0-1背包问题_递归_08


伪代码:

void KnapSack(int v[],int w[],int c,int n,int m[][11])

{

int jMax=min(w[n]-1,c);

for (j=0;j<jMax;j++)

m[n][j]=0;

for (j=w[n];j<=c;j++) // 当j>=w[n]时, m(n,j)=v[n]

m[n][j]=v[n];

for (i=n-1;i>=1;i--)

{

int jMax=min(w[i]-1,c);

for (j=0;j<jMax;j++)

m[i][j]=m[i+1][j];

for (j=w[i];j<=c;j++) //当j>=w[n],m(n,j)=v[n]

m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);

}

cout<<m[1][c];

}

要知道哪个物体被选中了,只需使用倒推法:

void traceback(int m[][11],int w[],int c,int n,int x[])

{ for(i=1;i<n;i++)

if (m[i][c]==m[i+1][c])

x[i]=0;

else

{x[i]=1;c=c-w[i];}

x[n]=(m[n][c]>0 ? 1:0);

}

源代码:

#include<bits/stdc++.h>
using namespace std;
int n,c;
int m[2000][2000];
void Knapsack(int *v,int *w,int c,int n)
{
int jMax = min(w[n]-1,c);
for(int j=0;j<=jMax;j++)/*
当 0=<j<w[n]时, 并不能将物体放入背包,m(n,j)=0
*/
m[n][j] = 0;
for(int j=w[n];j<=c;j++)// 当j>=w[n]时, m(n,j)=v[n]
m[n][j] = v[n];
for(int i=n-1;i>1;i--)
{
jMax = min(w[i]-1,c);
for(int j=0;j<=jMax;j++)//当0=<j<w[i],m(i,j)=m(i+1,j)
m[i][j] = m[i+1][j];
for(int j=w[i];j<=c;j++)
m[i][j] = max(m[i+1][j],m[i+1][j-w[i]]+v[i]);//当j>=w[n],m(n,j)=v[n]
}
m[1][c] = m[2][c];
if(c>=w[1])
{
m[1][c] = max(m[1][c],m[2][c-w[1]]+v[1]);
}
//自此,m[i][j]表填充完毕
}


void Traceback(int *w,int c,int n,int *x)
{
for(int i=1;i<n;i++)
if(m[i][c] == m[i+1][c])//如果第一个m【i】【c】的价值等于m【i+1】【c】,则物品i未装入
x[i] = 0;
else//否则装入,容量减去w【i】
{
x[i] = 1;
c-=w[i];
}
x[n] = (m[n][c])?1:0;//最后一个m【n】【c】大于0则代表装入,否则,未装入
}
int main()
{
cout<<"输入物品个数n:";
cin>>n;
cout<<endl;
int w[n+1];
int v[n+1];
cout<<"请依次输入每个物品的重量:"<<endl;
for(int i=1;i<=n;i++)
{
cin>>w[i];
}
cout<<"请输依次入每个物品的价值:"<<endl;
for(int i=1;i<n+1;i++)
{
cin>>v[i];
}
cout<<"输入背包容量c:";
cin>>c;
Knapsack(v,w,c,n);
int x[n+1];
Traceback(w,c,n,x);
cout<<endl<<"背包最大价值为"<<m[1][c]<<endl;
for(int i=1;i<n+1;i++)
{
if(x[i]==1)
cout<<"将第"<<i<<"件物品放入背包"<<endl;
}
cout<<"填充的m【1-4】【0-5】表"<<endl;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=c;j++)
{
cout<<m[i][j]<<" ";
}
cout<<endl;
}
return 0;
}

测试结果(测试用例即上面幻灯片例子):

算法:0-1背包问题_0-1背包_09


举报

相关推荐

0 条评论