算法:背包问题

背包问题用逆序减少空间复杂度的情况下,


//背包问题,如果是多维背包(质量,容积,个数),则加矩阵维度;如果是01背包,则逆序内循环,如果是完全背包(每种物品个数不限),则顺序内循环,如果是混合背包(限制每种物品的个数)。

#include<iostream>
using namespace std;
#define MAXN 110
#define MAXK 110



//给定整数集合, 元素个数为N,给定整数K,存在A的一个子集其和恰好为K吗?O(NK) ,如1,3,5,6,则9恰好等于1+3+5或6+3
bool KP_justk(int a[], int n, int k)
{
bool full[MAXN][MAXK];
int i,j;
for(i=1;i<=n;i++)
full[i][0]=true;
for(i=1;i<=k;i++)
full[0][i]=false;
full[0][0]=true;
for(i=1;i<=n;i++)
for(j=1;j<=k;j++)
if( full[i-1][j] || (j-a[i-1]>=0&&full[i-1][j-a[i-1]]) ) //注意递推关系,这里是i-1。 
full[i][j]=true;
else
full[i][j]=false;

return full[n][k];
}
///---------Just_k--------


//----01背包问题,给定N个物品重量w1,w2,....,wn, 价值p1,p2,....,pn,背包负重大小W, 求最大的价值,并表示出此时装入的物品 
//动态规划O(NW)
#define MAXVAL 110

void print_kp01(int (*rec)[MAXVAL], int w[], int p[], int i, int j)
{
if(i==0||j==0)
return;
if(rec[i][j]){
print_kp01(rec,w,p,i-1,j-w[i-1]);
cout<<i-1<<" w: "<<w[i-1]<<" p: "<<p[i-1]<<endl;
}
else
print_kp01(rec,w,p,i-1,j);
}
 
int KP_01(int w[], int p[], int n, int bigw) //O(NW)空间 
{
int val[MAXN][MAXVAL];
int rec[MAXN][MAXVAL];
int i,j;
for(i=1;i<=bigw;i++)
val[0][i]=0;
for(i=1;i<=n;i++)
val[i][0]=0;
val[0][0]=0;
for(i=1;i<=n;i++)
for(j=1;j<=bigw;j++)
if(j>=w[i-1]&& (val[i-1][j-w[i-1]]+p[i-1]) > val[i-1][j]){ // 如果加上等于则是尽量使背包中的物品数最多 
val[i][j] = (val[i-1][j-w[i-1]]+p[i-1]);
rec[i][j] = 1;
}
else{
val[i][j] = val[i-1][j];
rec[i][j] = 0;
}
print_kp01(rec,w,p,n,bigw);
return  val[n][bigw];
}


int KP_01_(int w[], int p[], int n, int bigw) //O(W)空间 (如果想输出具体的一组特例还是需要两层循环)
{
int val[MAXVAL];
int i,j;
for(i=0;i<=bigw;i++)
val[i]=0;
for(i=1;i<=n;i++)
for(j=bigw;j>=1;j--)
if(j>=w[i-1]&& (val[j-w[i-1]]+p[i-1]) >val[j])
val[j] = (val[j-w[i-1]]+p[i-1]);
return  val[bigw];
}
//----01背包问题--------



//--------------完全背包---------每种物品的个数无限制---- (如果想输出具体的一组特例还是需要三层循环)
int KP_complete(int w[], int p[], int n, int bigw) //O(W)空间 
{
int val[MAXVAL];
int i,j;
for(i=0;i<=bigw;i++)
val[i]=0;
for(i=1;i<=n;i++)
for(j=1;j<=bigw;j++)//跟01背包问题只有顺序逆序的差别,巧妙! 
if(j>=w[i-1]&& (val[j-w[i-1]]+p[i-1]) >val[j])
val[j] = (val[j-w[i-1]]+p[i-1]);

return  val[bigw];
}
//--------------完全背包------------ 



//--------------混合背包问题-------------每种物品的个数只能取n个
//转化为01背包问题

//--------------混合背包问题-------------



//---------------二维费用背包---加一个维度即可----如总物品最多能取M件(或背包体积是多大),假设是在01背包的基础上 
int KP_doublecost(int w[], int p[], int n, int bigw, int m) //O(W)空间 
{
int val[MAXVAL][MAXVAL];
int i,j,c;
for(i=0;i<=bigw;i++)
for(j=0;j<=m;j++)
val[i][j]=0;
for(i=1;i<=n;i++)
for(j=bigw;j>=1;j--)//跟01背包问题只有顺序逆序的差别,巧妙!
for(c=m;c>=1;c--) 
if( j>=w[i-1]&& (val[j-w[i-1]][c-1]+p[i-1]) > val[j][c])
val[j][c] = (val[j-w[i-1]][c-1]+p[i-1]);

return  val[bigw][m];
}
//---------------二维费用背包-------



int main()
{
loop:
int a[]={8,3,4,9,10},b[]={9,2,6,3,10},k,bigw;
//cout<<"k: ";
//cin>>k;
//cout<<KP_justk(a,5,k)<<endl;
//for(int i=1;i<=100;i++)
//if(!KP_justk(a,5,i))
//cout<<i<<" can't be full!"<<endl;
cout<<"bigw: ";
cin>>bigw;
cout<<KP_01(a,b,sizeof(a)/sizeof(a[0]),bigw)<<endl;
//cout<<KP_01_(a,b,sizeof(a)/sizeof(a[0]),bigw)<<endl;
cout<<KP_complete(a,b,sizeof(a)/sizeof(a[0]),bigw)<<endl;
cout<<KP_doublecost(a,b,sizeof(a)/sizeof(a[0]),bigw,4)<<endl;
goto loop;

return 0;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值