0-1背包:问题描述,NOIP 2001 装箱问题
有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30,每个物品有一个体积(正整数)。
要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
剩下最少的体积。
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 ",min); v=v-w[i]; dfs(i+1,v); //继续搜索下一位置的节点 //注意,搜索完后需要回溯处理,因为当前的i节点是(取或不取)两种情况都考虑 //前面部分是取了该节点,向下搜索,接下来V的值回溯,不取该节点,继续下搜索 v=v+w[i]; // printf("v=%d "); } } 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 ",min); return 0; }