• 各种背包乱搞


    01背包

    #include<iostream>
    using namespace
    int f[1005];//体积小于等于i的情况下最大价值是多少 
    int main()
    {
        int n,m;
        cin >> n >> m; 
        for(int i=1;i<=n;i++)
        {
            int v,w;
            cin >> v >>  w;
            for(int j=m;j>=v;j--)//从大到小是因为没有重复计算 
            {                    //从小到大算的话f[i-v]这个状态之前被算过了 
                f[j]=max(f[j],f[j-v]+w);    
           }
        }
        cout<<f[m]<<endl;
        return 0;
    }

    完全背包

    #include<iostream>
    using namespace std;
    int f[1005];//体积小于等于i的情况下最大价值是多少 
    int main()
    {
        int n,m;
        cin >> n >> m;
        for(int i=1;i<=n;i++)
        {
            int v,w;
            cin >> v >> w; 
            for(int j=v;j<=m;j++)//因为物品可以取无限次,那么从小到大 
            {                    //枚举 正好可以利用之前重复算过的 
                f[j]=max(f[j],f[j-v]+w);
            }
        }
        cout<<f[m]<<endl;
        return 0;
    }

    二维费用(体积,重量)

    /*做法类比01背包,加上枚举重量的循环就可以了*/
    
        #include<iostream>
        using namespace std;
        int f[1005][1005];//体积小于等于i,重量小于等于j的情况下最大价值是多少 
        int main()
        {
            int n,m,t;
            cin >> n >> m >> t;
            for(int i=1;i<=n;i++)
            {
                int v,s,w;
                cin >> v >> s >>w; 
                for(int j=m ;j>=v;j--)
                {
                    for(int k=t;k>=s;k--)
                    {
                        f[j][k]=max(f[j][k],f[j-v][k-s]+w); 
                    }
                }
            }
            cout<<f[m][t]<<endl;
            return 0;
         }

    分组背包

        #include<iostream>
        using namespace std;
        int f[1005];//表示前i组物品体积不超过j的情况下的最大价值 
        int v[105];
        int w[105];
        int main()
        {
            int n,m;
            cin >> n>> m;
            for(int i=1;i<=n;i++)
            {
                int s;
                cin >> s;
                for(int j=1;j<=s;j++) cin>> v[j]>> w[j];
                for(int j=m;j>=0;j--)
                {
                    for(int k=1;k<=s;k++)
                    {
                        if(j>=v[k])
                        {
                            f[j]=max(f[j],f[j-v[k]]+w[k]);
                        }
                    }
                }
             }
             cout<<f[m]<<endl;
             return 0;
         } 

    多重背包

    1.枚举num

    for(int i=1;i<=n;i++)//枚举物品
        for(int j=V;j>=0;j--)//枚举体积
            for(int k=1;k<=num[i],k++)
                //这个枚举到num[i]更省心
                if(j-k*c[i]>=0)//判断能否装下.
                    f[j]=max(f[j],f[j-k*c[i]]+k*w[i]);

    2.二进制拆分

    用$1,2,4...2^n$可以表示出$2^{n+1}-1$以内所有的正整数

    那么对1到$num[i]$进行拆分 得到多件大物品($1,2,4,8...$件物品的和)

    之后跑01背包

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=num[i];j<<=1)
        //二进制每一位枚举.
        //注意要从小到大拆分
        {
            num[i]-=j;//减去拆分出来的
            new_c[++tot]=j*c[i];//合成一个大的物品的体积
            new_w[tot]=j*w[i];//合成一个大的物品的价值
        }
        if(num[i])//判断是否会有余下的部分.
        //就好像我们某一件物品为13,显然拆成二进制为1,2,4.
        //我们余出来的部分为6,所以需要再来一份.
        {
            new_c[++tot]=num[i]*c[i];
            new_w[tot]=num[i]*w[i];
            num[i]=0;
        }
    }

    单调队列优化

    for(int i=1;i<=n;i++)//枚举物品种类 
    {
        cin>>c[i]>>w[i]>>num[i];//c,w,num分别对应 体积,价值,个数 
        if(V/c[i] <num[i]) num[i]=V/c[i];//求lim
        for(int mo=0;mo<c[i];mo++)//枚举余数 
        {
            head=tail=0;//队列初始化 
            for(int k=0;k<=(V-mo)/c[i];k++) 
            {
                int x=k;
                int y=f[k*c[i]+mo]-k*w[i];
                while(head<tail && que[head].pos<k-num)head++;//限制长度
                while(head<tail && que[tail-1].value<=y)tail--;
                que[tail].value=y,que[tail].pos=x;
                tail++;
                f[k*c[i]+mo]=que[head].value+k*w[i];
                //加上k*w[i]的原因:
                //我们的单调队列维护的是前i-1种的状态最大值.
                //因此这里加上k*w[i].
            }
        }
    }

    复杂度$O(n*V)$

    有依赖的背包

    多级附件:

    建树存先根遍历preo[],子树大小size[]

    设w[]为代价,v[]为价值

    先用一个虚点作为超级祖先

    转移时 对于某个节点,如果购买它,考虑它的子节点

    如果不购买,跳过它的子树

    for(int i=scc;i>=1;i--)
        {
            int node=preo[i];
            for(int j=m;j>=0;j--)
            {
                if(j<w[node])dp[i][j]=dp[i+siz[node]][j];
                else 
                dp[i][j]=max(dp[i+1][j-w[node]]+v[node],dp[i+siz[node]][j]);
            }
        }
  • 相关阅读:
    the selected directory is not a TomEE home
    java 获取当前年份 月份,当月第一天和最后一天
    java jwt工具类,生成和解析token
    Thymeleaf嵌套循环,每次循环显示固定数量
    oracle 非正常关机 错误1033解决办法
    webService简单记录
    好用的json工具
    org.apache.ws.commons.schema.XmlSchemaForm.getValue()Ljava/lang/String;
    webservice获取ip地址
    JSP(一)
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11192655.html
Copyright © 2020-2023  润新知