• 01背包


    423. 采药

    思路: 裸的01背包,背包容量V,n个物品,有重量v和价值w,一次只能选一个。dp[i,j]表示前i件商品中选择,体积不超过j可获得的最大价值。求可获得最大的价值。01背包的内存优化从大到小枚举体积。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1010,M=110;
    int dp[N];
    int t[M],v[M];
    int main(){
        int n,m;
        cin>>m>>n;
        for(int i=1;i<=n;++i)
            cin>>t[i]>>v[i];
        for(int i=1;i<=n;++i){
            for(int j=m;j-t[i]>=0;--j){
                dp[j]=max(dp[j-t[i]]+v[i],dp[j]);
            }
        }
        cout<<dp[m]<<endl;
        return 0;
    }
    

    1024. 装箱问题

    思路: dp[i,j]表示前i件商品中选择,体积恰好为j。任何体积都由dp[0,0]转移过来。

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

    278. 数字组合

    思路: dp[i,j]表示从前i件商品中选择体积恰好为j的选法

    #include<bits/stdc++.h>
    using namespace std;
    long long dp[10010];
    int main(){
        int n,m;
        cin>>n>>m;
        dp[0]=1;
        for(int i=1,v;i<=n;++i){
            cin>>v;
            for(int j=m;j-v>=0;--j){
                dp[j]+=dp[j-v];
            }
        }
        cout<<dp[m]<<endl;
        return 0;
    }
    

    1022. 宠物小精灵之收服

    思路: 二维费用01背包。f[i,j,k]表示从前i件商品中选择V1不超过j,V2不超过k的最大价值,可的获得最大价值。注意皮卡丘的体力不能为0,答案为dp[n,V1,V2-1].

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1010,M=510;
    int dp[N][M];
    int main(){
        int V1,V2,n;
        cin>>V1>>V2>>n;
        for(int i=1;i<=n;++i){
            int v1,v2;
            cin>>v1>>v2;
            for(int j=V1;j-v1>=0;--j){
                for(int k=V2-1;k-v2>=0;--k){
                    dp[j][k]=max(dp[j-v1][k-v2]+1,dp[j][k]);
                }
            }
        }
        cout<<dp[V1][V2-1]<<" ";
        int Max=V2-1;
        while(Max>0&&dp[V1][Max-1]==dp[V1][V2-1]) Max--;
        cout<<V2-Max<<endl;
        return 0;
    }
    

    1020. 潜水员

    思路: 需要求体积1超过V1,体积2超过V2的前提获得的最小价值。因为这道题可理解为求较大的体积,定义f[i,j,k]前i中商品中选择体积1至少是j,体积2至少是k获得的最少价值。做法和01背包一样,只是初始化的区别,还有y总总结的背包问题状态关于体积不同的顶一下,初始化的方式:

    #include<bits/stdc++.h>
    using namespace std;
    const int M=30,N=80;
    int f[M][N];
    int main(){
        int V1,V2,n;
        cin>>V1>>V2>>n;
        memset(f,0x3f,sizeof f);
        f[0][0]=0;
        for(int i=1,v1,v2,w;i<=n;++i){
            cin>>v1>>v2>>w;
            for(int j=V1;j>=0;--j){
                for(int k=V2;k>=0;--k){
                    f[j][k]=min(f[max(0,j-v1)][max(0,k-v2)]+w,f[j][k]);
                }
            }
        }
        cout<<f[V1][V2]<<endl;
        return 0;
    }
    

    12. 背包问题求具体方案

    思路: 根据最大值,从选择物品的放方向枚举,判断当前物品下剩余体积的价值是否对应,对应就选择,然后扩展到下一物品。因为要按照字典序最小输出,所以最后枚举答案要从1n,所以01背包从n1开始做。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1100;
    int f[N][N],v[N],w[N],way[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){
            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]);
            }
        }
        int j=m,tot=0;
         for(int i=1;i<=n;++i){
            if(j-v[i]>=0&&f[i][j]==f[i+1][j-v[i]]+w[i]){
                way[tot++]=i;
                j-=v[i];
            }
         }
         for(int i=0;i<tot;++i)
            cout<<way[i]<<" ";
    }
    

    11. 背包问题求方案数

    思路: 因为要统计具体的方案数,所以避免容斥。状态定义为:f[i,j]前i种商品总选择,体积恰好是j件可获得的最大价值,g[i,j]前i种商品总选择,体积恰好是j件可获得的最大价值的方案数。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1001;
    const int mod=1e9+7;
    int f[N],num[N];
    int main(){
        int n,m;
        cin>>n>>m;
        memset(f,-0x3f,sizeof f);
        num[0]=1;
        f[0]=0;
        for(int i=1,w,v;i<=n;++i){
            cin>>v>>w;
            for(int j=m;j>=v;--j){
                int maxv=max(f[j-v]+w,f[j]),cnt=0;
                if(maxv==f[j-v]+w) cnt+=num[j-v];
                if(maxv==f[j]) cnt+=num[j];
                num[j]=cnt%mod;
                f[j]=maxv;
            }
        }
        int maxv=0;
        for(int j=0;j<=m;++j){
            maxv=max(maxv,f[j]);
        }
        int res=0;
        for(int j=0;j<=m;++j){
            if(f[j]==maxv) res=(res+num[j])%mod;
        }
        cout<<res<<endl;
        return 0;
    }
    

    734. 能量石
    思路: 首先显然有一个贪心思路(类似国王的游戏很容易证明),(s_i*l_i<s_j*l_j),选择的顺序就是i<j。所以先按s*l升序排序。然后根据题目中的定义直接做01背包。01背包需要定义为体积恰好是j,因为问题对时间的要求是精准的,而不是一个范围。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=10010; 
    struct stone{
      int s,e,l;
      bool operator<(const stone & b)const {
          return s*b.l<b.s*l;
      }
    }a[N];
    int f[N];
    int main(){
        int T;
        cin>>T;
        for(int cas=1;cas<=T;++cas){
            int n,m=0;
            cin>>n;
            for(int i=1;i<=n;++i){
                cin>>a[i].s>>a[i].e>>a[i].l;
                m+=a[i].s;
            }
            sort(a+1,a+1+n);
            memset(f,-0x3f,sizeof f);
            f[0]=0;
            for(int i=1;i<=n;++i){
                int s=a[i].s,e=a[i].e,l=a[i].l;
                for(int j=m;j>=s;--j){
                    f[j]=max(f[j],f[j-s]+e-(j-s)*l);
                }
            }
            int res=0;
            for(int i=0;i<=m;++i) res=max(res,f[i]);
            cout<<"Case #"<<cas<<": "<<res<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    网站开发综合技术 一 JavaScript简介 二JavaScript语法
    网站开发综合技术 第二部分 CSS样式表
    网站开发综合技术 第一部分HTML 1.3.2表单
    网站开发综合技术 HTML
    C#基础 结构体 枚举类型
    C#基础 out传值
    C#基础 函数部分
    C#基础 特殊集合
    ASP.NET MVC案例教程(基于ASP.NET MVC beta)——第一篇:准备工作
    ASP.Net中页面传值的几种方式
  • 原文地址:https://www.cnblogs.com/jjl0229/p/12570952.html
Copyright © 2020-2023  润新知