zoukankan      html  css  js  c++  java
  • 11道背包问题

    传送门

    1.01背包

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1005;
    int f[N];
    int n,V,v,w;
    int main(){
        cin>>n>>V;
        for(int i=0;i<n;i++){
            cin>>v>>w;
            for(int j=V;j-v>=0;j--){
                f[j]=max(f[j],f[j-v]+w);
            }
        }
        cout<<f[V]<<endl;
        return 0;
    }

    2.完全背包

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1005;
    int n,V,v,w;
    int f[N];
    int main(){
        cin>>n>>V;
        for(int i=0;i<n;i++){
            cin>>v>>w;
            for(int j=0;j<=V;j++){
                if(j-v>=0)f[j]=max(f[j],f[j-v]+w);
            }
        }
        cout<<f[V]<<endl;
        return 0;
    }

    3. 多重背包问题 I 普通写法o(n^3)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1005;
    int n,V,v,w,s;
    int f[N];
    int main(){
        cin>>n>>V;
        for(int i=0;i<n;i++){
            cin>>v>>w>>s;
            for(int j=V;j>=0;j--){
                for(int k=1;k<=s;k++){
                    if(j-k*v>=0)f[j]=max(f[j],f[j-k*v]+k*w);
            }
        }
        }
        cout<<f[V]<<endl;
        return 0;
    }

    4.多重背包问题 II 二进制拆分o(n^2logs)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=4000005;
    int n,V,v,w,s;
    int f[N],a[N],b[N];
    int main(){
        int cnt=1,m;
        cin>>n>>V;
        for(int i=0;i<n;i++){
            cin>>v>>w>>s;
            for(int j=1;j<=s;j<<=1){
                b[cnt]=j*w;
                a[cnt++]=j*v;
                s-=j;
            }
            if(s>0){
                b[cnt]=s*w;
                a[cnt++]=s*v;
            }
        }
        for(int i=1;i<cnt;i++){
            for(int k=V;k>=0;k--){
                if(k-a[i]>=0){
                    f[k]=max(f[k],f[k-a[i]]+b[i]);
                }
            }
        }
        cout<<f[V]<<endl;
        return 0;
    }

    5.多重背包问题 III 单调队列(困难,待补坑)

    6.混合背包问题

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1005;
    int a[N*N],b[N*N],c[N*N],f[N];
    int main(){
        int n,v,inf=0;
        cin>>n>>v;
        for(int i=0;i<n;i++){
            int v,w,s;
            cin>>v>>w>>s;
            if(!s){//完全
                a[inf]=v;
                b[inf]=w;
                c[inf++]=0;
            }
            else{
                if(s==-1){
                    a[inf]=v;
                    b[inf]=w;
                    c[inf++]=1;//01
                }
                else{//多重背包
                    int k=1;
                    while(k<=s){
                        a[inf]=k*v;
                        b[inf]=k*w;
                        c[inf++]=1;
                        s-=k;
                        k<<=1;
                    }
                    if(s){
                        a[inf]=s*v;
                        b[inf]=s*w;
                        c[inf++]=1;
                    }
                }
            }
        }
        for(int i=0;i<inf;i++){
            if(c[i]==0){
                for(int j=a[i];j<=v;j++){
                    f[j]=max(f[j],f[j-a[i]]+b[i]);
                }
            }
            else{
                for(int j=v;j>=a[i];j--){
                    f[j]=max(f[j],f[j-a[i]]+b[i]);
                }
            }
        }
        cout<<f[v]<<endl;
        return 0;
    }

    7. 二维费用的背包问题

    满足体积和重量两种要求

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1005;
    int f[N][N];
    int a[N],b[N],c[N];
    int main(){
        int n,v,m;
        cin>>n>>v>>m;
        for(int i=0;i<n;i++){
            int v,m,w;
            cin>>v>>m>>w;
            a[i]=v,b[i]=m,c[i]=w;
        }
        for(int i=0;i<n;i++){
            for(int j=v;j>=a[i];j--){
                for(int z=m;z>=b[i];z--){
                     f[j][z]=max(f[j][z],f[j-a[i]][z-b[i]]+c[i]);
                }
            }
        }
        cout<<f[v][m]<<endl;
        return 0;
    }

    8. 分组背包问题

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1005;
    int f[N];
    int a[N][N],b[N][N],c[N];
    int main(){
        int n,v,m,inf=0;
        cin>>n>>v;
        for(int i=0;i<n;i++){
            int s,v,w;
            cin>>s;
            c[i]=s;
            for(int j=0;j<s;j++){
                cin>>v>>w;
                a[i][j]=v,b[i][j]=w;
            }
        }
        for(int i=0;i<n;i++){
            for(int j=v;j>=0;j--){
                for(int k=0;k<c[i];k++){
                    if(j>=a[i][k]){
                        f[j]=max(f[j],f[j-a[i][k]]+b[i][k]);
                    }
                }
            }
        }
        cout<<f[v]<<endl;
        return 0;
    }

    9. 有依赖的背包问题

     

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1005;
    vector<int>a[N];
    int n,m,root,son;
    int v[N],w[N];
    int f[N][N];///代表当前节点u最大体积为v的最大价值
    void dfs(int u){
        for(int i=v[u];i<=m;i++){
            f[u][i]=w[u];///根节点的值先赋值
        }
        for(int i=0;i<a[u].size();i++){///枚举子树
            int son=a[u][i];
            dfs(son);///递归子树
            for(int j=m;j>=v[u];j--){///从大到小枚举(01背包),j必须大于v[u]才能存放根节点
                for(int k=0;k<=j-v[u];k++){///k是留给子树的容量,k必须小于等于j-v[u]才能保证根节点能存放
                    f[u][j]=max(f[u][j],f[u][j-k]+f[son][k]);
                }
            }
        }
    }
    int main(){
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            int V,W,p;
            cin>>V>>W>>p;
            if(p==-1){
                root=i;
                v[root]=V;
                w[root]=W;
            }
            else{
                a[p].push_back(i);
                v[i]=V;
                w[i]=W;
            }
        }
        dfs(root);
        cout<<f[root][m]<<endl;
        return 0;
    }

    10.背包问题求方案数

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1005;
    const int mod = 1e9+7;
    int f[N],g[N];
    int main(){
        int n,m;
        cin>>n>>m;
        g[0]=1;///初始化
        for(int i=0;i<n;i++){
            int v,w;
            cin>>v>>w;
            for(int j=m;j>=v;j--){
                int s=0;///当前最优价值的方案数
                int t=max(f[j],f[j-v]+w);
                if(t==f[j])s+=g[j];///最大值是f[j]
                if(t==f[j-v]+w)s+=g[j-v];///也可以是两者值相等,则方案数相加
                f[j]=t;
                g[j]=s;///更新
                g[j]%=mod;
            }
        }
        int maxx=-1;
        for(int i=0;i<=m;i++){
            maxx=max(maxx,f[i]);///取出最大价值
        }
        int res=0;
        for(int i=0;i<=m;i++){
            if(f[i]==maxx){///判断当前体积能否达到最大价值,可以就加上方案数
                res+=g[i];
            }
            res%=mod;
        }
        cout<<res<<endl;
        return 0;
    }

     11.背包问题求具体方案,要求输出字典序最小的具体方案

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1005;
    const int mod = 1e9+7;
    int f[N][N];///f[i][j]代表第i个元素到最后元素的最大价值
    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=n;i>=1;i--){///从后往前,最后得到的f[1][m]是1到n的最大价值
            for(int j=0;j<=m;j++){
                f[i][j]=f[i+1][j];
                if(j>=v[i]){
                    f[i][j]=max(f[i+1][j],f[i+1][j-v[i]]+w[i]);
                }
            }
        }
        int s=m;
        for(int i=1;i<=n;i++){///字典序要尽量小,则从前往后找
            if(v[i]<=s&&f[i][s]==f[i+1][s-v[i]]+w[i]){///如果第i个被选中
                printf("%d ",i);
                s-=v[i];///减掉该物品的体积
            }
            if(s<=0)break;
        }
        return 0;
    }

     

  • 相关阅读:
    【PL/SQL练习】函数
    【PL/SQL练习】命名块: 存储过程、函数、触发器、包
    【PL/SQL练习】自定义异常
    织梦首页/列表页文章按权重排序
    织梦dede:channel取子栏目时重复显示同级栏目的解决方法
    织梦最新版后台一键更新网站、更新文档HTML卡死的解决方法
    虚拟主机二级域名(m.dedehtml.com)绑定到织梦子目录(m)做手机站
    织梦自定义表单数据校验不对的解决方法
    织梦自定义表单用js代替联动地区解决联动地区选择
    织梦自定义图片字段调用图片地址
  • 原文地址:https://www.cnblogs.com/mohari/p/13729386.html
Copyright © 2011-2022 走看看