2/17 01背包+完全背包+多重背包(二进制优化)+二位费用背包+dfs

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2/17 01背包+完全背包+多重背包(二进制优化)+二位费用背包+dfs相关的知识,希望对你有一定的参考价值。

多重背包(二进制优化) ------------------小吐槽:我还以为很难学呢,just so so~
https://www.luogu.com.cn/problem/P1833

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
int h1,h2,m1,m2;
int n,w,ti[maxn],c[maxn],f[maxn],cnt;

int main()

    scanf("%d:%d",&h1,&m1);scanf("%d:%d",&h2,&m2);
    w=(h2-h1)*60-m1+m2;

    scanf("%d",&n);
    for(int i=1;i<=n;i++)    //转化为01背包
    
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z); //价值/重量/件数
        if(!z)
        
            z=999999;
        
        int t=1;
        while(z>=t)
        
           ti[++cnt]=x*t;
           c[cnt]=y*t;
           z-=t;
           t<<=1;
        
        if(z)
        
            ti[++cnt]=x*z;
            c[cnt]=y*z;
        
    
    for(int i=1;i<=cnt;i++)
    
        for(int j=w;j>=ti[i];j--)
            f[j]=max(f[j],f[j-ti[i]]+c[i]);
    
    cout<<f[w]<<endl;
    return 0;


https://www.luogu.com.cn/problem/P1776

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
int n,w,v[maxn],c[maxn],f[maxn];

int main()

    int cnt=1;
    scanf("%d%d",&n,&w);
    for(int i=1;i<=n;i++)    //转化为01背包
    
        int x,y,z;scanf("%d%d%d",&x,&y,&z); //价值/重量/件数
        int t=1;
        while(z>=t)
        
           v[cnt]=x*t;
           c[cnt++]=y*t;
           z-=t;
           t<<=1;
        
        if(z)
        
            v[cnt]=x*z;
            c[cnt++]=y*z;
        
    
    cnt--;
    for(int i=1;i<=cnt;i++)
    
        for(int j=w;j>=c[i];j--)
        
            f[j]=max(f[j],f[j-c[i]]+v[i]);
        
    
    cout<<f[w]<<endl;
    return 0;


经典深搜题:有助于理解深搜
https://www.luogu.com.cn/problem/P2066

#include <bits/stdc++.h>

using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=20;
int n,m,a[maxn][maxn],f[maxn],ans[maxn],cnt;

void dfs(int id,int sum,int rest) //公司编号,利润,生育机器

    if(rest<0) return;
    if(id==n+1)
    
        if(sum>cnt)
        
            cnt=sum;
            for(int i=1;i<=n;i++)
                f[i]=ans[i];
        
        return;
    
    for(int i=0;i<=m;i++)  //机器从0开始分配,有些公司可没有机器
    
        ans[id]=i;  //记录几台
        dfs(id+1,sum+a[id][i],rest-i);
    

int main()

    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        scanf("%d",&a[i][j]);
    dfs(1,0,m);
    cout<<cnt<<endl;
    for(int i=1;i<=n;i++)
        cout<<i<<" "<<f[i]<<endl;
    return 0;


https://www.luogu.com.cn/problem/P1509
二维费用背包:
附加要求:约到数量最多的女孩,还要花的钱最少的时间
开两个二维数组分别记录

#include <bits/stdc++.h>

using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=105;
int n,m,r,rmp[maxn],rp[maxn],f1[maxn][maxn],f2[maxn][maxn];
int ti[maxn];
int main()

    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    
        scanf("%d%d%d",&rmp[i],&rp[i],&ti[i]);
    
    scanf("%d%d",&m,&r);
    for(int i=1;i<=n;i++)
    
        for(int v=m;v>=rmp[i];v--)
        
            for(int u=r;u>=rp[i];u--)
            
               int n1=f1[v][u];
               int n2=f1[v-rmp[i]][u-rp[i]]+1;  //约到女孩的数量
               int t1=f2[v-rmp[i]][u-rp[i]]+ti[i];  //约到女孩花的时间

               f1[v][u]=max(n1,n2);
               if(n1==n2)  //若数量相等取时间少的
                    f2[v][u]=min(f2[v][u],t1);

               else if(n2>n1)  //数量多的优先,记录时间
                    f2[v][u]=t1;
            
        
    
    int ans=inf;
    for(int i=1;i<=m;i++)
    
        for(int j=1;j<=r;j++)
            if(f1[m][r]==f1[i][j])
            ans=min(ans,f2[i][j]);
    
    cout<<ans<<endl;
    return 0;

https://www.luogu.com.cn/problem/P1853
完全背包:
注意不断更新s的值

#include <bits/stdc++.h>

using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e8+5;
int s,n,d,a[50],b[50],f[maxn];

int main()

    scanf("%d%d%d",&s,&n,&d);
    for(int i=1;i<=d;i++)
        scanf("%d%d",&a[i],&b[i]);

    for(int i=1;i<=n;i++)  //年数
    
        for(int j=1;j<=d;j++)  //债券的完全背包
        
            for(int k=a[j];k<=s;k++)
                f[k]=max(f[k],f[k-a[j]]+b[j]);
        
        s+=f[s];  //加上每年的利息f[s]
    
    cout<<s<<endl;
    return 0;


https://www.luogu.com.cn/problem/P2370
01背包+快排(根据题意)
注:虽然01背包队物品排列并不关心,但根据排序是非常必要的

#include <bits/stdc++.h>

using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1005;
int n,p,s,dp[maxn],ans=inf,tmp;
struct node

    int a,b;
e[maxn];
bool cmp(node e1,node e2)

    return e1.a<e2.a;

int main()

    scanf("%d%d%d",&n,&p,&s);
    for(int i=1;i<=n;i++)
    
        scanf("%d%d",&e[i].a,&e[i].b);
    
    sort(e+1,e+n+1,cmp);
    for(int i=1;i<=n;i++)
    
        for(int j=s;j>=e[i].a;j--)
        
            dp[j]=max(dp[j],dp[j-e[i].a]+e[i].b);
            if(dp[j]>=p)
            
               cout<<e[i].a<<endl;
               return 0;
            
        
    
    cout<<"No Solution!"<<endl;
    return 0;

https://www.luogu.com.cn/problem/P2725
完全背包吧所有情况都罗列出来,如果需要的邮票数还是初始化的inf,则上一个数字就是答案

#include <bits/stdc++.h>

using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e7+5;
int k,n,f[maxn],ans;

int main()

    scanf("%d%d",&k,&n);
    memset(f,inf,sizeof(f));
    f[0]=0;
    for(int i=1;i<=n;i++)
    
        int x;scanf("%d",&x);
        for(int j=x;j<=maxn;j++)
        
            if(f[j-x]+1<=k)
                f[j]=min(f[j],f[j-x]+1);
        
    
    for(int i=1;i<=maxn;i++)
    
        if(f[i]==inf)
        
            ans=i-1;break;
        
    
    cout<<ans<<endl;
    return 0;

以上是关于2/17 01背包+完全背包+多重背包(二进制优化)+二位费用背包+dfs的主要内容,如果未能解决你的问题,请参考以下文章

多重背包并判断能否装满(附01完全背包思想)

背包DP

混合背包问题

HDU 3591 (完全背包+二进制优化的多重背包)

背包整理(01背包,完全背包,多重背包,分组背包)(待更新)

AcWing 5. 多重背包问题 II(二进制优化)