背包问题

                      背包问题(要不断更新)

一.01背包

Q:N物品,T容量,Wi消耗,Vi价值,每件物品取一个,怎样价值最大?(还记得在清北手推了二维的转移方程,但现在并不知道倒序的原理)

    for(int i=1;i<=n;i++){//放到第i件物品 
        for(int j=T;j>=0;j--){//倒序,防止重复往里面放 
            if(j>=weight[i]){
            dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
            }    
            else{
                dp[j]=dp[j];
            }    
        }
    }//dp[j]代表当容量为j时的最大价值

注意:倒序j

二.完全背包

Q:N物品,T容量,Wi消耗,Vi价值,每件物品取随意个,怎样价值最大?

    for(int i=1;i<=n;i++){
        for(int j=weight[i];j<=T;j++){
            dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);            
        }
    }

注意:正序j

三.多重背包

Q:N物品,T容量,Wi消耗,Vi价值,每件物品取Ni个,怎样价值最大?

    for(int i=1;i<=n;i++){
        for(int j=T;j>=0;j--){
            for(int k=0;k<=s[i];k++){
                if(j-k*weight[i]<0)break;
                dp[j]=max(dp[j],dp[j-k*weight[i]]+k*value[i]);
            }
        }
    }

二进制优化还不会qaq一定要学会回头再编辑!

四.二维背包

Q:N物品,T1容量,T2容量,Wi1消耗,Wi2消耗,,Vi价值,每件物品取1个,怎样价值最大?

    for(int i=1;i<=n;i++){
        for(int j=T1;j>=v[i];j--){
            for(int k=T2;k>=m[i];k--){
                dp[j][k]=max(dp[j][k],dp[j-v[i]][k-m[i]]+value[i]);
            }
        }
    }

多加一维,多for一个量的01背包

五.混合背包

N物品,T容量,,Wi消耗,,V价值,有的物品取1个,有的物品取随意个,有的物品取s[i]个,怎样价值最大?(s[i]为0为随意)

    for(int i=1;i<=n;i++){
        if(s[i]==0){//完全 
            for(int j=weight[i];j<=T;j++){
                dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
            }
        }
        else{//01,多重 
            for(int k=1;k<=s[i];k++){
                for(int j=T;j>=weight[i];j--){
                    dp[j]=max(dp[j],dp[j-weight[i]]+value[i])
                }
            }
        }    
    }

六.分组背包

N组物品,每组只可以选一个,T容量,怎样取价值最大?

    for(int i=1;i<=n;i++){
        cin>>weight[i]>>value[i]>>x;
        t=max(t,x);//求组数
        b[x]++;//这一组中的序号++ 
        g[x][b[x]]=i;//组里第n个为第i个的信息  
    }
    for(int i=1;i<=t;i++){
        for(int j=T;j>=0;j--){
            for(int k=1;k<=b[i];k++){
                if(j>=weight[g[i][k]]){
                    dp[j]=max(dp[j],dp[j-weight[g[i][k]]]+value[g[i][k]]);
                }
            }
        }
    }

多for组,再for容量,最后for每组的元素,注意预处理

七.有依赖性的背包

N物品,里面有主件也有附件,买附件就必须买主件,每个主件最多有两个附件,问怎样价值最大?

    for(int i=1;i<=n;i++){
        cin>>m>>v>>p;
        if(p>0) f[i]=p;
        else if(p==0) f[i]=i;//判断是否为主件 
        //只买主件、主件+附件1,主件+附件2,主件+附件1+附件2,不买    
        if(i==f[i]){
            weight[i][0]=m;//本身 
            value[i][0]=m*v;
        }
        else{//附件 
            if(flag[p]==1){//是第一个附件 
                weight[p][1]=m;
                value[p][1]=v*m;
                flag[p]=2;
            } 
            else if(flag[p]==2){//是第二个附加 
                weight[p][2]=m;
                value[p][2]=v*m;
            }                        
        }     
    }
    dp[0]=0;
    for(int i=1;i<=n;i++){
        if(weight[i][0]>0){
            for(int j=T;j>=weight[i][0];j--){
                if(j>=weight[i][0]){
                dp[j]=max(dp[j],dp[j-weight[i][0]]+value[i][0]);//只买主件 
                }
                if(j>=weight[i][1]+weight[i][0]){                               //只买附件一和.. 
                dp[j]=max(dp[j],dp[j-weight[i][1]-weight[i][0]]+value[i][1]+value[i][0]);
                }
                if(j>=weight[i][2]+weight[i][0]){                                //只买附件二和.. 
                dp[j]=max(dp[j],dp[j-weight[i][2]-weight[i][0]]+value[i][2]+value[i][0]);
                }
                if(j>=weight[i][1]+weight[i][2]+weight[i][0]){        //都买 
                dp[j]=max(dp[j],dp[j-weight[i][1]-weight[i][2]-weight[i][0]]+value[i][1]+value[i][2]+value[i][0]); 
                }
            }
        }
    } 
待到oi十一月,我花开后百花杀。
原文地址:https://www.cnblogs.com/china-mjr/p/11223149.html