2335: 0-1背包问题
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 98 Solved: 61
[ Submit][ Status][ Web Board]
Description
试设计一个用回溯法搜索子集空间树的函数。该函数的参数包括结点可行性判定函数和上界函数等必要的函数,并将此函数用于解0-1背包问题。 0-1 背包问题描述如下:给定n 种物品和一个背包。物品i 的重量是wi ,其价值为vi ,背包的容量为C。应如何选择装入背包的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有2 种选择,即装入背包或不装入背包。不能将物品i 装入背包多次,也不能只装入部分的物品i。
Input
第一行有2个正整数n和c。n是物品数,c是背包的容量。接下来的1 行中有n个正整数,表示物品的价值。第3 行中有n个正整数,表示物品的重量。
Output
将计算出的装入背包物品的最大价值和最优装入方案输出。第一行输出为:Optimal value is
Sample Input
5 10
6 3 5 4 6
2 2 6 5 4
Sample Output
Optimal value is
15
1 1 0 0 1
#include<cstdio>#include<cstring>#include<cmath>#include<set>#include<cstdlib>#include<iostream>#include<algorithm>using namespace std;#define MAXN 202#define INF 999999int main(){ int dp[105][105],v[105],w[105],vis[105]; int n,V; scanf("%d%d",&n,&V); for(int i=0; i<n; i++) scanf("%d",&v[i]); for(int i=0; i<n; i++) scanf("%d",&w[i]); memset(dp,0,sizeof(dp)); for(int i=0; i<n; i++) for(int j=0; j<=V; j++) { if(j<w[i]) dp[i+1][j]=dp[i][j]; else dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i]); } int k=V;// for(int i=0;i<=n;i++)// {// for(int j=0;j<=V;j++)// cout<<dp[i][j]<<" ";// cout<<endl;// } for(int i=n;i>0;i--) { if(dp[i][k]>dp[i-1][k]) { vis[i-1]=1;//从最后面一个开始判断,是否前i种物品在V质量内所组成价值大于前i-1种,如果是那就是 k-=w[i-1];//说明将第i种物品加入到背包当中去 } else vis[i-1]=0; }// for(int i=0;i<n;i++)// cout<<vis[i]<<" ";// cout<<endl; puts("Optimal value is"); printf("%d\n",dp[n][V]); int i; for(i=0; i<n; i++) printf("%d ",vis[i]); printf("\n"); return 0;}注意:采用不同的dp循环方式,得到的答案(这里仅指选择的种类)可能不一,但最终的最大值是一样的
如 n=4, (w,v)={(2,3) (1,2) (3,4) (2,2)} V=5;
采用上面的就是1010
但是dp如果是这样
for(int i=n-1; i>=0; i--)
for(int j=0; j<=V; j++)
{
if(j<w[i])
dp[i][j]=dp[i+1][j];
else
dp[i][j]=max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]);
}