/* *背包问题 1.形式化描述 给定: 物品i的重量是wi,价值为vi,背包容量为c; 其中c>0,wi>0,vi>0,iE[1,n],找出一个n元向量X,使得 WX <= c,此时 VX 最大. 这是一个特殊的整数规划问题 * 2.子问题为 背包容量为j可选物品为i,i+1,...,n时的背包问题,定义为 m(i,j) 从而,递归定义如下: 当 j>=wj时, m(i,j) = max( m(i+1,j),m(i+1,j-wj)+vj) //可以装时,选出装与不装的最大的 当 j<wj时,m(i,j) = m(i+1,j) //装不下就不装 其中,递归退出时: m(n,j) = vn; j>wn; m(n,j) = 0; j<wn; 算法实现,用m[][]来存储m(i,j) * */ //01knapsack //给定: 物品i的重量是wi,价值为vi,背包容量为c; // 其中c>0,wi>0,vi>0,iE[1,n],找出一个n元向量X,使得 WX <= c,此时 VX 最大. #include <iostream> #include<iomanip.h> #include<string.h> using namespace std; int min(int w,int c) { return (w<c)? w:c; } int max(int w,int c) { return (w>c)? w:c; } void knapsack(int val[],int wei[],int c,int n,int**m) //求最优值 { //仅可选n时,容量为j的子问题的最优值 int jmax=min(wei[n]-1,c); for(int j=0;j<=jmax;j++) m[n][j]=0; for(int jj=wei[n];jj<=c;jj++) m[n][jj]=val[n]; for(int i=n-1;i>1;i--) { //递归部分 //仅可选i时,容量为j的子问题的最优值 jmax=min(wei[i]-1,c); for(int j=0;j<=jmax;j++) m[i][j]=m[i+1][j]; for(int jj=wei[i];jj<=c;jj++) m[i][jj]=max(m[i+1][jj],m[i+1][jj-wei[i]]+val[i]); } m[1][c]=m[2][c]; if(c>=wei[1]) m[1][c]=max(m[1][c],m[2][c-wei[1]]+val[1]); cout<<"最优值:"<<m[1][c]<<endl; cout<<endl; } /****************最优值,根据最优子结构的性质,X计算如下: * m1c == m2c => x1=0 * * if x1=0, m2c == m3c => x2=0, * if x1=1, m2(c-w1) == m3c => x2=0, * ... * * ***************************************/ int traceback(int **m,int wei[],int c,int n,int x[]) //回代,求最优解 { cout<<"得到的一组最优解如下:"<<endl; for(int i=1;i<n;i++) { if(m[i][c]==m[i+1][c]) x[i]=0; else { x[i]=1; c-=wei[i]; } x[n]=(m[n][c])?1:0; if(i == (n-1)) cout<<"得到了最佳方案如下: "<<endl; for(int y=1;y<=n;y++) { cout<<setw(5)<<x[y]; } cout<<endl; } return x[n]; } int main() { int n,c; cout<<"请输入物品个数和重量上限:"; cin>>n>>c; int *val=new int[n+1];//动态一维数组 cout<<"Pls input the "<<n<<" property (val[i]):"<<endl; for(int i=1;i<=n;i++) cin>>val[i]; int *wei=new int[n+1]; cout<<"Pls input the "<<n<<" weight (w[i]):"<<endl; for(int j=1;j<=n;j++) cin>>wei[j]; //定义二维数组,n+1 * c+1 存放子问题的最优值m(i,j) int **m=new int*[n+1];//分配了n+1 个指针数组,m[i] 为一个 *m, //为每一行分配内存 for(int i=0;i<(n+1);i++) { m[i] = new int[c+1];//int *p = new int[n]; 因为m[i] 代表每一个 *m,所以这里不是 *m[i] } //分配答案的结果 int *x=new int[n+1]; knapsack(val,wei,c,n,m); traceback(m,wei,c,n,x); //=============================== delete[] val,wei,x; for(int i=0;i<n+1;i++) { delete[] m[i]; } delete[] m; return 1; }