0—1背包问题,回溯实现

     0-1背包:问题描述,NOIP 2001 装箱问题

有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0n<=30,每个物品有一个体积(正整数)。

要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。


       动态规划考虑:容量为V的箱子,最多能装多少单位体积的物品Vmax,V-Vmax即为

      剩下最少的体积。

      s[v]表示容积为v的箱子,最多能装的物品体积

      则对当前的物品m,动态转移方程:

      s[v]=max{ s[v],s[v-w[m]]+w[m] }

      实现:

       

   for(i=0;i<n;i++)
     {
       for(j=v;j>=w[i];j--)
       if(s[j-w[i]]+w[i]>s[j])
       s[j]=s[j-w[i]]+w[i];
     }

       深度搜索考虑:

       深度搜索:以一个点为起点,向下搜索,直到末尾节点为止。但是要注意,搜索中节点回溯(即某个节点,在搜索的过程中,可以添加,也可以不添加的情况处理)

       

#include <stdio.h>
#include <stdlib.h>
/*
  有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30,
  每个物品有一个体积(正整数)。
  要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
  这是一个典型的0—1背包型问题,可以采用搜索(深搜)、动态规划等方法 
  深度搜索:以一个点为起点,向下搜索,直到末尾节点为止。但是要注意,搜索中节点回溯
  (即某个节点,在搜索的过程中,可以添加,也可以不添加的情况处理) 
*/
int V,n,w[31],min;


int dfs(int k,int v)   //深度搜索 
{
	if(k>=n||v<=0) return 0; //搜索结束的情况 
	int i,j;
	for(i=k;i<n;i++)         //分别在[k,n]区间内,以各个点为起点,向下深搜 
	{
		if(v-w[i]>=0)       //该节点在限制范围内可以添加 
		{
			if(v-w[i]<min) min=v-w[i];  //将该节点添加进来 
	//		printf("min=%d\n",min);
			v=v-w[i];
			dfs(i+1,v);     //继续搜索下一位置的节点 
	//注意,搜索完后需要回溯处理,因为当前的i节点是(取或不取)两种情况都考虑
	//前面部分是取了该节点,向下搜索,接下来V的值回溯,不取该节点,继续下搜索 
			v=v+w[i];        
	//		printf("v=%d\n");
		}
	}
	return 0;
}
  
int main(int argc, char *argv[]) {
	
	int i,j;
	freopen("npack.in","r",stdin);
	freopen("npack.out","w",stdout);
	scanf("%d%d",&V,&n);
	for(i=0;i<n;i++) scanf("%d",&w[i]);
	min=V;
	dfs(0,V);
	printf("%d\n",min);
	return 0;
}

posted @ 2014-06-01 10:19  _tham  阅读(186)  评论(0编辑  收藏  举报