01背包问题

01背包问题

假设你有一个背包,最多能承重M千克,这里有N个物品,其重量分别为w1、w2、……、wN,其价值分别为v1、v2、……、vN,在背包所能承受的重量下,尽可能得使背包里的价值最大。(注意,该物品只能放或者不放,不能只放该物品的0.8这样子,非0即1,故称为01背包问题)

二维数组

f[i][j]表示装到第i个物体,背包内不超过j千克时,最大的价值数

#include <iostream>
using namespace std;
 
const int N=1010;
int v[N],w[N],f[N][N];
int n,m;
 
int main()
{
  scanf("%d%d",&n,&m);
  
  for(int i=1;i<=n;i++) scanf("%d%d",&v[i],&w[i]);
  
  for(int i=1;i<=n;i++)
    for(int j=1;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]);
    }    
 
  printf("%d",f[n][m]); 
  return 0;
}

一维数组

是二维数组的一种优化,可以看到,遍历到当前物体的结果只与前一个物体的结果有关,并不需要记录每一个物体的结果。

#include <iostream>
using namespace std;
 
const int N=1010;
int v[N],w[N],f[N];
int n,m;
 
int main()
{
  scanf("%d%d",&n,&m);
  
  for(int i=1;i<=n;i++) scanf("%d%d",&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]);
    }
    
  printf("%d",f[m]);
  return 0;
}

牛客【2021】阿里巴巴编程题(4星)

7.牛牛们吃糖果
有n个牛牛一起去朋友家吃糖果,第i个牛牛一定要吃ai块糖果.而朋友家一共只有m块糖果,可能不会满足所有的牛牛都吃上糖果。同时牛牛们有k个约定,每一个约定为一个牛牛的编号对(i,j),表示第i个和第j个牛牛是好朋友,他俩要么一起都吃到糖果,要么一起都不吃。
保证每个牛牛最多只出现在一个编号对中。
您可以安排让一些牛牛吃糖果,一些牛牛不吃。
要求使能吃上糖果的牛牛数量最多(吃掉的糖果总量要小于等于m),并要满足不违反牛牛们的k个约定。

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 256M,其他语言512M

思路

把一对牛牛合成一个,对应的value变为2,就转换成了01背包问题

代码

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

int main() {
    int n,m;
    cin>>n>>m;
    vector<vector<int>> a(n,vector<int>(2,1));
    for(int i=0;i<n;i++){
        cin>>a[i][0];
    }
    int k;
    cin>>k;
    for(int i=0;i<k;i++){
        int u,v;
        cin>>u>>v;
        a[u-1][0]+=a[v-1][0];
        a[u-1][1]=2;
        a[v-1][1]=0;
        a[v-1][0]=0;
    }
    // sort(a.begin(),a.end(),[](vector<int> i,vector<int> j){
    //     if(i[0]==j[0]) return i[1]>j[1];
    //     else return i[0]<j[0];
    // });
    vector<int> dp(m+1);
    
    for(int i=0;i<n;i++){
        for(int j=m;j>=a[i][0];j--){
            dp[j]=max(dp[j],dp[j-a[i][0]]+a[i][1]);
        }
    }


    cout<<dp[m];
    return 0;
}
// 64 位输出请用 printf("%lld")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值