01背包问题

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">
</span>

0-1背包问题是一个特殊的整数规划问题。



设所给0-1背包问题的子问题



的最优值为m(i,j),即m(i,j)是背包容量为j,可选择物品为i,i+1,…,n时0-1背包问题的最优值。由0-1背包问题的最优子结构性质,可以建立计算m(i,j)的递归式如下。



算法复杂度分析:
从m(i,j)的递归式容易看出,算法需要O(nc)计算时间。当背包容量c很大时,算法需要的计算时间较多。例如,当c>2n时,算法需要Ω(n2n)计算时间。

下面是自己写的一段代码:

// 01背包算法经典法.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
using namespace std;
int max(int a,int b){
	if(a>=b){
		return a;
	}
	else{
		return b;
	}
}
int min(int a,int b){
	if(a<b){
		return a;
	}
	else{
		return b;
	}
}
void Knapsack(int *v,int *w,int c,int n,int m[][100]){//计算背包中所有物品的最大价值
	int JMax=min(w[n]-1,c);
	for(int j=0;j<=JMax;j++)m[n][j]=0;
	for(int j=w[n];j<=c;j++)m[n][j]=v[n];
	for(int i=n-1;i>=1;i--){//最后一个物品放不放入的运算,放在循环里或者循环外都是可以的,区别是循环外就少算了m[1][0]到m[1][c-1],因为这些在计算中用不到了。
		JMax=min(w[i]-1,c);
		for(int j=0;j<=JMax;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]);
	}
	//m[1][c]=m[2][c];
	//if(c>=w[1])m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]);
	cout<<m[1][c]<<endl;
}

void Traceback(int m[][100],int *w,int c,int n,int *x){
	for(int i=1;i<n;i++){
		if(m[i][c]==m[i+1][c])x[i]=0;
		else{x[i]=1;c-=w[i];}
		x[n]=(m[n][c])?1:0;
	}
	for(int i=1;i<=n;i++){
		if(x[i]==1){
			cout<<i<<" ";
		}
	}
}
int _tmain(int argc, _TCHAR* argv[])
{
	int c;//c代表背包的容量
	int v[100];//每一个v代表第i个物品的价值
	int w[100];//每一个w代表第i个物品的重量
	int n;//n代表总的物品个数
	int m[100][100];//m[][]存放动态规划的计算结果
	int x[100];//x[]存放第i个物品是否被放入背包
	cout<<"输入背包的容量:";
	cin>>c;
	cout<<"输入物品总数:";
	cin>>n;
	for(int i=1;i<=n;i++){
		cout<<"输入第"<<i<<"个物品的重量和价值:";
		cin>>w[i]>>v[i];
	}
	Knapsack(v,w,c,n,m);
	Traceback(m,w,c,n,x);
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值