栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

动态规划背包问题优化模板(完整代码)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

动态规划背包问题优化模板(完整代码)

01背包(每个物品只能取一次)
01背包和完全背包优化区别在于01是倒序,完全是正序
/*我们每次计算dp[j] (即dp[i][j]) 的时候都会需要dp[j-w[i]]
(即dp[i-1][j-w[i]])的值。
因为j-w[i]比j小,所以如果我们正序计算,(正序用完全,因为完全可以重复,不需要考虑更新)
那么dp[j-w[i]]就已经更新了 (即dp[i][j-w[i]]),与状态转移方程不符。

#include
using namespace std;
int n,m,v[1001],w[1001],f[1001],g[1001];
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("%dn",f[m]);
}

完全背包(每个物品可取多次)

#include
using namespace std;
int n,m,v[1001],w[1001],f[1001],g[1001];
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=v[i];j<=m;j++){
                f[j]=max(f[j],f[j-v[i]]+w[i]);
        }
    }
    printf("%dn",f[m]);
    system("pause");
}

多重背包(规定一个物品可以取多次,转换成01背包问题)

(数学方法:1,2,...,2^m选一些数字相加,可以得出[0,2^(m+1))
#include
using namespace std;
int n,m,v[2001],w[2001],f[2001],l[2001];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&v[i],&w[i],&l[i]);
    }
    for(int i=1;i<=n;i++){
        int res=l[i];
        for(int k=1;k<=res;res-=k,k*=2)//切成l份    
            for(int j=m;j>=v[i]*k;j--){
                f[j]=max(f[j],f[j-v[i]*k]+w[i]*k);
            }
        for(int j=m;j>=v[i]*res;j--)//多出来的,好比8=1+2+4+1,多出来一个1
            f[j]=max(f[j],f[j-v[i]*res]+w[i]*res);
    }
    printf("%dn",f[m]);
    system("pause");
}
利用单调队列思想
#include
using namespace std;
int n,m,v,w,t,f[10001],c[10001][2];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i <= n; i++){
        scanf("%d%d%d",&v,&w,&t);
        for(int j=0; j < v; j++){
            int k=0,l=1;
            for(int p=j,x=1; p <= m;p+=v,++x){
                int e=f[p]-x*w,r=x+t;
                for(; k >= l && c[k][0] <= e;--k);
                c[++k][0]=e;c[k][1]=r;
                f[p]=c[l][0]+w*x;
                for(; k >= l && c[l][1] == x; ++l);
            }
        }
    }
    printf("%dn",f[m]);
    system("pause");
}

分组背包(每个物品属于哪个组,且一个组只能拿一个)

#include
using namespace std;
int n,m,v[1001],w[1001],a[1001],f[1001];
vector c[1001];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1; i <= n; i++){
        scanf("%d%d%d",&a[i],&v[i],&w[i]);
        c[a[i]].push_back(i);
    }
    for(int i=1; i <= 1000; i++)
        for(int j=m; j > 0; j--){
            for(auto k:c[i])//k是一个下标,枚举选这组里的几种选择
                if(v[k]<=j)
                    f[j]=max(f[j],f[j-v[k]]+w[k]);
        }
    printf("%dn",f[m]);
    system("pause");
}

二维背包(多了个体力这个限制条件(不一定是体力))

#include
using namespace std;
int n,m,v[1001],w[1001],t[1001],f[101][101],k;
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1; i <= n; i++)
        scanf("%d%d%d",&v[i],&w[i],&t[i]);
    for(int i=1; i<=n; i++)
        for(int j=m; j >= v[i]; j--)
            for(int x=k; x >= t[i]; x--){
                    f[j][x]=max(f[j][x],f[j-v[i]][x-t[i]]+w[i]);
            }
    printf("%dn",f[m][k]);
    system("pause");
}

混合背包(就是01,完全,多重混在一起),由于多重的单调队列思想方法不是很好写,这边就用数学结论的方法

#include
using namespace std;
int n,m,k[10001],v[10001],w[10001],f[10001],l[10001];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1; i <= n ;i++){
        cin>>k[i]>>v[i]>>w[i];
        if(k[i]==3){
            cin>>l[i];
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(k[i]==2)//完全背包
        {
            for(int j=v[i];j<=m;j++){
                f[j]=max(f[j],f[j-v[i]]+w[i]);
            }
        }
        if(k[i]==1){
            for(int j=m;j>=v[i];j--){
                f[j]=max(f[j],f[j-v[i]]+w[i]);
            }
        }
        else//多重背包和01
        {
            int res=l[i];
        for(int p=1;p<=res;res-=p,p*=2)//切成l份    
            for(int j=m;j>=v[i]*p;j--){
                f[j]=max(f[j],f[j-v[i]*p]+w[i]*p);
            }
        for(int j=m;j>=v[i]*res;j--)//多出来的,好比8=1+2+4+1,多出来一个1
            f[j]=max(f[j],f[j-v[i]*res]+w[i]*res);
            
        }
    }
    cout<
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/878964.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号