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

这篇博客探讨了多种动态规划在解决背包问题上的应用,包括多重背包、01背包、完全背包以及二维费用背包问题。通过实例展示了如何将实际问题转化为01背包或完全背包,并利用动态规划求解,同时强调了排序和优化技巧的重要性。
摘要由CSDN通过智能技术生成

多重背包(二进制优化) ------------------小吐槽:我还以为很难学呢,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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值