动态规划之01背包问题+状态压缩(hihocode#1038)

01背包问题解释详见博客:

https://blog.csdn.net/mu399/article/details/7722810

此博客主要介绍如何减低空间复杂度,对应题目hihocode #1038

1.先附上最普通没有任何优化的写法

#include <cstdio>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
ll val[600];
ll wei[600];
ll ans[600][100010];
int main()
{
  ll n,m;
  cin>>n>>m;
  for(int i=0;i<=m;i++)
      ans[0][i]=0;
  for(int i=1;i<=n;i++)
  {
    cin>>wei[i]>>val[i];
  }
  for(int i=1;i<=n;i++)
  {
    for(int j=0;j<=m;j++)
    {
      if(j>=wei[i])
        ans[i][j]=max(ans[i-1][j],ans[i-1][j-wei[i]]+val[i]);
      else
        ans[i][j]=ans[i-1][j];
    }
  }
  cout<<ans[n][m]<<endl;
}

2.状态压缩写法,状态转移方程为ans[i][j]=max(ans[i-1][j],ans[i-1][j-wei[i]]+val[i]),观察这个式子发现每次我们只关心状态i与装态i-1的情况所以空间复杂度可以压缩为2*M;

#include <cstdio>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
ll val[600];
ll wei[600];
ll ans[2][100010];
int main()
{
  ll n,m;
  cin>>n>>m;
  for(int i=0;i<=m;i++)
      ans[0][i]=0;
  for(int i=1;i<=n;i++)
  {
    cin>>wei[i]>>val[i];
  }
  int t=0;
  for(int i=1;i<=n;i++)
  {
    t=(t+1)%2;
    for(int j=0;j<=m;j++)
    {
      if(j>=wei[i])
        ans[t][j]=max(ans[(t+1)%2][j],ans[(t+1)%2][j-wei[i]]+val[i]);
      else
        ans[t][j]=ans[(t+1)%2][j];
    }
  }
  cout<<ans[t][m]<<endl;
}

3.更低的写法,倒过来从j=m执行ans[i][j]=max(ans[i-1][j],ans[i-1][j-wei[i]]+val[i]),当ans[i][j]已经计算过了,就可以确定从ans[i-1][j]已经无用了,那么可以用ans[i-1[j]的位置存储ans[i][j],所以如果倒过来执行就只需1*m的空间

#include <cstdio>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
ll val[600];
ll wei[600];
ll ans[100010];
int main()
{
  ll n,m;
  cin>>n>>m;
  for(int i=0;i<=m;i++)
      ans[i]=0;
  for(int i=1;i<=n;i++)
  {
    cin>>wei[i]>>val[i];
  }
  for(int i=1;i<=n;i++)
  {
    for(int j=m;j>=0;j--)
    {
      if(j>=wei[i])
        ans[j]=max(ans[j],ans[j-wei[i]]+val[i]);
      else
        ans[j]=ans[j];
    }
  }
  cout<<ans[m]<<endl;
}


猜你喜欢

转载自blog.csdn.net/qq_30754565/article/details/80977592