您的位置:首页 > 其它

HDU 2602 Bone Collector 背包

2011-08-05 08:50 323 查看
该题是一道背包题,并且是一个0,1背包,这种背包特点是:每种物品仅有一件,可以选择放或不放。

用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:

f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int f[1024][1024];
int v[1024],w[1024];
int main(  )
{
int n,m,M;

scanf( "%d",&M );
for( int i=0; i< M; i++ )
{
memset( f,0,sizeof( f ) );
scanf( "%d%d",&n,&m );
for( int j=1; j<=n; j++ )
scanf( "%d",&w[j] );
for( int j=1; j<=n ;j++ )
scanf( "%d",&v[j] );
for( int j=1; j<=n; j++ )
for( int k=0; k<=m; k++ )
{
if( k>=v[j]&&f[ j-1 ][ k-v[j] ]+w[j]>f[j-1][k] )
f[j][k]=f[j-1][ k-v[j] ]+w[j];
else f[j][k]=f[j-1][k];
}
printf( "%d\n",f
[m] );
}
return 0;
}


  该题的第二种解法就是对背包的优化解法,当然只能对空间就行优化,时间是不能优化的,先考虑上面讲的基本思路如何实现,肯定是有一个主循环i=1..N,每次算出来二维数组f[i][0..V]的所有值。那么,如果只用一个数组f[0..V],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[i][v]呢?f[i][v]是由f[i-1][v]和f[i-1][v-c[i]]两个子问题递推而来,能否保证在推f[i][v]时(也即在第i次主循环中推f[v]时)能够得到f[i-1][v]和f[i-1][v-c[i]]的值呢?事实上,这要求在每次主循环中我们以v=V..0的顺序推f[v],这样才能保证推f[v]时f[v-c[i]]保存的是状态f[i-1][v-c[i]]的值。伪代码如下:

for i=1..N

for
v=V..0

f[v]=max{f[v],f[v-c[i]]+w[i]};

注意:这种解法只能由V--0,不能反过来,如果反过来就会造成物品重复放置!

#include<stdio.h>
#include<stdlib.h>
int  DP(int w[],int v[],int N,int M)
{
int f[1024]={0};
for( int i=1; i<=N; i++ )
{
for( int j=M; j>=0; j-- )
{
if( j>=v[i]&&f[ j ]<f[j-v[i]]+w[i] )
f[ j ]= f[ j-v[i] ] + w[i];
}
}
return f[M];
}
int  main()
{
int n,N,M;
int v[1005],w[1005];
scanf( "%d",&n );
for( int i=0; i<n; i++  )
{
scanf( "%d%d",&N,&M );
for( int j=1; j<=N; j++ )
scanf( "%d",&w[j] );
for( int j=1; j<=N; j++ )
scanf( "%d",&v[j] );
printf( "%d\n",DP( w , v, N ,M ) );
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: