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]。
该题的第二种解法就是对背包的优化解法,当然只能对空间就行优化,时间是不能优化的,先考虑上面讲的基本思路如何实现,肯定是有一个主循环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,不能反过来,如果反过来就会造成物品重复放置!
用子问题定义状态:即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; }
相关文章推荐
- HDU 2602 Bone Collector 0/1背包
- HDU 2602 Bone Collector(最简单的0/1背包问题)
- hdu 2602 Bone Collector 01背包
- HDU 2602 Bone Collector (0-1背包)
- hdu 2602 Bone Collector 0-1背包问题
- HDU 2602 Bone Collector(01背包裸题)
- hdu 2602 Bone Collector 背包入门题
- HDU 2602 Bone Collector(0 1背包)
- HDU 2602 Bone Collector (简单的0-1背包)
- HDU 2602 Bone Collector(赤裸裸01背包)
- 【0-1背包复习】HDU 2602——Bone Collector
- HDU-2602 - Bone Collector - 01背包
- HDU 2602 Bone Collector 背包问题
- HDU 2602 Bone Collector(附01背包滚动数组的理解)
- hdu 2602 Bone Collector(0 1 背包简单入门)
- HDU 2602 Bone Collector(0/1背包)
- HDU 2602 Bone Collector (经典0-1背包)
- hdu-2602-Bone Collector-(0-1背包)
- hdu 2602 Bone Collector 01背包
- hdu 2602 Bone Collector (01 背包基础)