动态规划 背包问题

动态规划 背包问题

0-1背包

朴素版本

#include<iostream>

using namespace std;

int n,m;
int v[N],w[N];
int f[N][N];
int main()
{
  cin>>n>>m;
  for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
  for(int i=1;i<=n;i++)
  {
    for(int j=0;j<=m;j++)
    {
      f[i][j]=f[i-1][j];
      if(j>=v[i])
        f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
    }
  }
  cout<<f[n][m]<<endl;
  return 0;
}

优化版本

using namespace std;
const int N=1010;

int n,m;
int v[N],w[N];
int f[N];

int main(){
  cin>>n>>m;
  for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
  for(int i=1;i<=n;i++)
    for(int j=m;j>=v[i];j--)
      f[j]=max(f[j],f[j-v[i]]+w[i]);
  cout<<f[m]<<endl;
  return 0;
}

完全背包

从前i个物品中选择,总体积不大于j

朴素版本

#include<iostream>
using namespace std;
const int N=1010;
int f[N][N];
int v[N],w[N];

int main()
{
  int n,m;
  cin>>n>>m;
  for(int i=1;i<=n;i++)
  {
    cin>>v[i]>>w[i];
    
  }
  for(int i=1;i<=n;i++)
    for(int j=0;j<=m;j++)
    {
      for(int k=0;k*v[i]<=j;k++)
        f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
    }
 cout<<f[n][m]<<endl;
}

优化思路
我们列举一下更新次序的内部关系:

f [ i , j ] = m a x ( f [ i − 1 , j ] , f [ i − 1 , j − v ] + w , f [ i − 1 , j − 2 ∗ v ] + 2 ∗ w , f [ i − 1 , j − 3 ∗ v ] + 3 ∗ w , . . . . . ) f[i , j ] = max( f[i-1,j] , f[i-1,j-v]+w , f[i-1,j-2*v]+2*w , f[i-1,j-3*v]+3*w , .....) f[i,j]=max(f[i1,j],f[i1,jv]+w,f[i1,j2v]+2w,f[i1,j3v]+3w,.....)
f [ i , j − v ] = m a x ( f [ i − 1 , j − v ] , f [ i − 1 , j − 2 ∗ v ] + w , f [ i − 1 , j − 2 ∗ v ] + 2 ∗ w , . . . . . ) f[i , j-v]= max( f[i-1,j-v] , f[i-1,j-2*v] + w , f[i-1,j-2*v]+2*w , .....) f[i,jv]=max(f[i1,jv],f[i1,j2v]+w,f[i1,j2v]+2w,.....)
由上两式,可得出如下递推关系:
$ f[i][j]=max(f[i][j-v]+w , f[i-1][j]) $

优化

从小到大枚举

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1010;

int n,m;
int v[N],w[N];
int f[N];

int main(){
  cin>>n>>m;
  for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
  
  for(int i=1;i<=n;i++)
    	for(int j=v[i];j<=m;j++)
        f[j]=max(f[j],f[j-v[i]]+w[i]);
  
  cout<<f[m]<<endl;
  return 0;
}

多重背包

#include<iostream>
#include<algorithm>

using namespace std;

const int N=110;

int n,m;
int v[N],w[N],s[N];
int f[N][N];


int main()
{
  cin>>n>>m;
  
  for(int i=1;i<=n;i++) cin>>v[i]>>w[i]>>s[i];
  
  for(int i=1;i<=n;i++)
    for(int j=0;j<=m;j++)
      for(int k=0;k<=s[i]&&k*v[i]<=j;k++)
        f[i][j]=max(f[i][j],f[i-1][j-v[i]*k]+w[i]*k);
  cout<<f[n][m]<<endl;
  return 0;
}


多重背包优化

二进制的优化方式

f[i,j]=max(f[i-1],j,)

#include<iostream>
#include<algorithm>
using namespace std;

const int N=25000,M=2010;

int n,m;
int v[N],w[N];
int f[N];

int main()
{
  cin>>n>>m;
  int cnt=0;
  for(int i=1;i<=n;i++)
  {
    int a,b,s;
    cin>>a>>b>>c;
    int k=1;
    while(k<=s)
    {
      cnt++;
      v[cnt]=a*k;
      w[cnt]=b*k;
      s-=k;
      k*=2;
    }
    if(s>0)
    {
      cnt++;
      v[cnt]=a*s;
      w[cnt]=b*s;
      
    }
  }
  
  n=cnt;
  for(int i=1;i<=n;i++)
    for(int j=m;j>=v[i];j--)
      f[j]=max(f[j],f[j-v[i]]+w[i]);
  cout<<f[m]<<endl;
  
  return 0;
}

分组背包问题

#include<iostream>
#include<algorithm>
using namespace std;

const int n,m;
int v[N][N],w[N][N],s[N];
int f[N];

int main()
{
	cin>>n>>m;
  for(int i=1;i<=n;i++)
  {
    cin>>s[i];
    for(int j=0;j<s[i];j++)
      cin>>v[i][j]>>w[i][j];
  }
  
  for(int i=1;i<=m;i++)
    for(int j=m;i>=0;j--)
      for(int k=0;k<s[i];k++)
        if(v[i][k]<=j)
          f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);
  
  cout<<f[m]<<endl;
  
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值