0-1背包问题的优化

0-1背包问题的优化
http://202.120.80.191/problem.php?problemid=2585
f[i][j]表示前i件物品恰放入一个容量为j的背包可以获得的最大价值。则其状态转移方程便是:
f[i][v]=max{f[i-1][j],f[i-1][j-w[i]]+d[i]}
可以看出,第i个状态只和前一个状态有关。因此,只需要一个一维数组a[maxn],伪代码为
for ( int  i = 1 ;i <= n;i ++ )
   
for ( int  j = m;j >= w[i];j -- )
      a[j]
= max(a[j],a[j - w[i]]+d[i]);
注意,第二层循环要从后往前。max(a[j],a[j-w[i]])中,a[j]表示的是只考虑前i-1个物品,且背包容量是j时可以获得的最大值,即递推公式中的f[i-1][j],a[j-w[i]]则是f[i-1][j-w[i]].
该优化,把空间复杂度从O(mn)降到了O(m).

还有一个优化:
由于最后的结果是存放在a[m]中,而求a[m]只需要知道a[j-w[n]]即可,依次类推,当之考虑前i个物品时,只需要知道a[j-sum(n..i)]即可。 所以优化后的伪代码为:
for ( int  i = 1 ;i <= n;i ++ )
{
   bound
= max(w[i],m - sum[n.. 1 ]);
   
for ( int  j = m;j >= bound;j -- )
      a[j]
= max(a[j],a[j - w[i]] + d[i]);
}
#include  < iostream >
#include 
< algorithm >
#include 
< vector >
#include 
< string >
using   namespace  std;
const   int  maxn = 3403 ;
int  w[maxn],d[maxn],sum[maxn];
int  a[ 12881 ];
int  n,m;
void  solve()
{
    
int  bound;
    sum[n]
= w[n];
    
for ( int  i = n - 1 ;i > 0 ;i -- )
        sum[i]
= sum[i + 1 ] + w[i];
    
for ( int  i = 0 ;i <= m;i ++ )
        a[i]
= 0 ;
    
for ( int  i = 1 ;i <= n;i ++ )
    {
        
// bound=max(w[i],m-sum[i]);
        bound = w[i] > m - sum[i] ? w[i]:m - sum[i];
        
for ( int  j = m;j >= bound;j -- )
            a[j]
= a[j] > a[j - w[i]] + d[i] ? a[j]:a[j - w[i]] + d[i];
    }
    printf(
" %d\n " ,a[m]);
}
int  main()
{
    scanf(
" %d%d " , & n, & m);
    
for ( int  i = 1 ;i <= n;i ++ )
        scanf(
" %d%d " , & w[i], & d[i]);
    solve();
    
return   0 ;
}


你可能感兴趣的:(0-1背包问题的优化)