动态规划_背包问题

01背包问题

有N件物品和一个容量为V的背包。(每种物品均只有一件)第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。

未优化版本:

for (int i=1;i<=n;++i) { for (int j=v;j>=0;--j)   {
       if(c[i]<=j)//如果当前物品可以放入当前空间的背包
       f[i][j]=max(f[i-1][j],f[i-1][j-c[i]]+w[i]);
       else f[i][j]=f[i-1][j];//如果当前物品放不进去,那么继承前i个物品在当前空间大小时的价值
   }
  }

优化版本:

/*
01背包
适用于输入格式如下的问题,出现问题请自行调整:
第一行两个整数M, N分别表示背包空间与物品总数;
第2到N+1行每行两个整数,分别表示这类物品每个的价值和所需空间。 
*/
#include<cstdio>
const int MAXM=10001,MAXN=51;
int m,n;
int w[MAXN],c[MAXN];
int f[MAXM];
int max(int x,int y)
{
    return x>y?x:y;
}
int main()
{
    scanf("%d%d",&m,&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&w[i],&c[i]);
    for(int i=1;i<=n;i++)
        for(int j=m;j>=w[i];j--)
            f[j]=max(f[j],f[j-w[i]]+c[i]);
    printf("%d\n",f[m]);
    return 0;
}
01背包问题(完全背包)

未优化版本:

for(int i = 0 ; i < n ; i ++) 
{ 
    for(int j = 1 ; j <= v ; j++) 
    {
        if(c[i]<=j)
        f[i][j] = max(f[i-1][j],f[i][j-c[i]]+w[i]); 
        else
        f[i][j]=f[i-1][j];
    }
}

优化版本:

/*
完全背包,输入规则:
第一行两个整数M, N分别表示背包空间与物品总数;
第2到N+1行每行两个整数,分别表示这类物品每个的价值和所需空间。 
*/
#include<cstdio>
const int MAXM=10001,MAXN=51;
int m,n;
int w[MAXN],c[MAXN];
int f[MAXM];
int max(int x,int y)
{
    return x>y?x:y;
}
int main()
{
    scanf("%d%d",&m,&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&w[i],&c[i]);
    for(int i=1;i<=n;i++)
        for(int j=w[i];j<=m;j++)
            f[j]=max(f[j],f[j-w[i]]+c[i]);
    printf("%d\n",f[m]);
    return 0;
}

01背包问题(多重背包)

未优化版本:

#include<bits/stdc++.h>
using namespace std;
int dp[1005];
int weight[1005],value[1005],num[1005];
int main()
{
    int n,m;
    cin>>n>>m;
    memset(dp,0,sizeof(dp));
    for(int i=1; i<=n; i++)
        cin>>weight[i]>>value[i]>>num[i];
        
    for(int i=1; i<=n; i++)//每种物品
        
        for(int k=0; k<num[i]; k++)//其实就是把这类物品展开,调用num[i]次01背包代码
        
            for(int j=m; j>=weight[i]; j--)//正常的01背包代码
            
                dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
    
    cout<<dp[m]<<endl;
    return 0;
}

优化版本说明:

把原始的数量的物品拆分可以组合的多个商品,

比如Ci  = 14,我们可以把它化成如下4个物品:


重量是Wi,体积是Vi
重量是2 * Wi , 体积是2 * Vi
重量是4 * Wi , 体积是4 * Vi
重量是7 * Wi , 体积是7 * Vi

优化版本:

/*
多重背包,输入格式: 
第一行,一个整数n,物品数量;
第二行,n个整数,第i个整数表示第i个物品的价格bi;
第三行,n个整数,第i个整数表示第i个物品的数量ci;
第四行,一个整数m,背包空间。
*/
#include<cstdio>
const int MAXM=10001,MAXN=6001;
int v[MAXM],w[MAXM];
int f[MAXN];
int n,m,p;
int max(int x,int y)
{
    return x>y?x:y;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        int x,y,s,t=1;
        scanf("%d%d%d",&x,&y,&s);
        for(;s>=t;t<<=1)
        {
            v[++p]=x*t;
            w[p]=y*t;
            s-=t;
        }
        v[++p]=x*s;
        w[p]=y*s;
    }
    for(int i=1;i<=p;i++)
        for(int j=m;j>=v[i];j--)
            f[j]=max(f[j],f[j-v[i]]+w[i]);
    printf("%d\n",f[m]);
    return 0;
}

参考文章:

https://www.cnblogs.com/Kalix/p/7622102.html

https://www.cnblogs.com/frankchenfu/p/6445843.html

https://blog.csdn.net/tinyguyyy/article/details/51203935

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值