回溯篇---0-1背包问题NOJ1004

0-1背包问题:

时限:1000ms 内存限制:10000K 总时限:3000ms

问题描述:

需对容量为c 的背包进行装载。从n 个物品中选取装入背包的物品,每件物品i 的重量为wi ,价值为pi 。对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高。

输入:

多个测例,每个测例的输入占三行。第一行两个整数:n(n<=10)和c,第二行n个整数分别是w1到wn,第三行n个整数分别是p1到pn。
n 和 c 都等于零标志输入结束。

输出:

每个测例的输出占一行,输出一个整数,即最佳装载的总价值。

输入示例

回溯篇---0-1背包问题NOJ1004_第1张图片

输出示例在这里插入图片描述

基本思路

回溯篇---0-1背包问题NOJ1004_第2张图片
设n个物品,重量用数组w[1…n]存放,价值用v[1…n]存放,容量为c,用best[1…n]表示最优解,best[i]=0表示不放入背包,best[i]=1表示放入背包。由于每个物品要么装入,要么不装入,其解空间是一颗子集树,每个结点中有两个数值,前者表示放入背包中物品的总重量,后者表示总价值。

具体过程

见代码注释,因为之前写代码不太习惯写注释,所以每次在着手代码前会先描述下思路,忽然觉得这样不利于之后代码的复习,还是将过程具体到代码当中去了。

代码实现

#include 

using namespace std;

int n,c;//物品总数,背包容量
int w[100];//各物品重量
int v[100];//各物品价值

int c_w;//当前总质量
int c_v;//当前总价值
int best_v;//最优的价值

void dfs(int k);//回溯深搜
bool cut(int k);//剪枝
bool overweight(int k);


int main()
{
   scanf("%d %d",&n,&c);
  while(!(n==0&&c==0))
  {
   for(int i=0;i<n;i++)
   
	   scanf("%d",&w[i]);
   
   for(i=0;i<n;i++)
   
	   scanf("%d",&v[i]);

   c_v=0,c_w=0,best_v=0;
    dfs(0);

	printf("%d",best_v);

	scanf("%d %d",&n,&c);
  }

	return 0;
}

void dfs(int k)
{
	//if(k=n)看看这个傻逼错误吧……
	if(k==n)//搜到最后一个物品,且当前价值大于最优价值,则更新最优价值
	{
		if(best_v<c_v)
		{
			best_v=c_v;
		}
	}
	else
	{
		if(!cut(k))
		{
			if(!overweight(k))//判断是否超重
			{
				c_w+=w[k];
				c_v+=v[k];
				
				dfs(k+1);

				c_w-=w[k];//回溯到上有一节点
				c_v-=v[k];
			}
            dfs(k+1);
		}
	}
}

bool cut(int k)
{
	int v_remain=0;
    for(int i=k;i<n;i++){
        v_remain+=v[i];     //计算物品m及剩下的所有物品价值
    }
    if(c_v+v_remain<best_v)    //如果当前价值和剩下所有物品价值加起来
        return true;        //都不如当前的vmax大,则没必要再搜下去
    else
        return false;

}
bool overweight(int m)   //判断是否超重
{
    if(c_w+w[m]>c)       //若装入物品m超重
        return true;
    else
        return false;
}

来更新一波,学完dp后再次尝试……

#include 

using namespace std;

#define max(x,y) ((x)>(y)?(x):(y))

int n;//物品数量
int maxvalue;//最大可装重量 
int dp[1001][1001];//dp数组 
int w[1001],v[1001];//重量和价值数组 

void solve();//解题函数 

int main()
{
	cin>>n>>maxvalue;//输入数量,重量

	for(int i=1;i<=n;i++){
		cin>>w[i];//输入重量 
	}
	for(i=1;i<=n;i++){
		cin>>v[i];//输入价值 
	}
	solve(); 
	return 0;
}


void solve(){
	for(int i=0;i<=n;i++){
		for(int j=0;j<=maxvalue;j++){
			if(i==0 || j==0) 
				dp[i][j]=0;//边界dp,结果为0 
			else
			{
				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]);//装得下,max比较装或不装哪个更大 
			}
		}
	}
	cout<<dp[n][maxvalue]<<endl;//输出结果 
}

你可能感兴趣的:(算法,dfs)