背包问题

#include<iostream>
using namespace std;
int a[210][210],b[210],c[40];
int max(int,int);
int n,m,maxn;
int main()
{
    cin>>m>>n;
    for(int i=1;i<=n;i++)
        cin>>b[i]>>c[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=m;j++)
        {
            for(int k=0;k<=1;k++)
            {
                a[i][j]=a[i-1][j];
                if(j>=b[i]*k) a[i][j]=max(a[i][j],a[i-1][j-k*b[i]]+c[i]*k);
            }
            
        }
    }
    cout<<"max="<<a[n][m];
    return 0;
}
int max(int x,int y)
{
    if(x>y) return x;
    else return y;
}

这是最简单的一种背包问题的最简单的实现方式

二维数组好理解但是太浪费空间了,很容易让数据范围太小或空间超限,总之就是很烦

#include<iostream>
using namespace std;
int a[100000];
int n,wi,ci,w;
int main()
{
    cin>>w>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>wi>>ci;
        for(int j=w;j>=wi;j--)
        {
            a[j]=max(a[j],ci+a[j-wi]);
        }
    }
    cout<<a[w];
    return 0;
}

这是一维数组的实现,但是一定要记住:j是从w倒着循环到wi的

然后就是01背包求方案数

#include<iostream>
using namespace std;
int a[100000],b[100000];
int n,wi,ci,w;
int main()
{
    cin>>n>>w;
    a[0]=1;
    for(int i=1;i<=n;i++)
        cin>>b[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=w;j>=b[i];j--)
        {
            a[j]=a[j]+a[j-b[i]];
        }
    }
    cout<<a[w];
    return 0;
}

每次都有选与不选两种决策,只需要加起来就好了

(其实我也没太看懂

完全背包:

#include<iostream>
using namespace std;
int a[100000];
int n,wi,ci,w;
int main()
{
    cin>>w>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>wi>>ci;
        for(int j=wi;j<=w;j++)
        {
            a[j]=max(a[j],ci+a[j-wi]);
        }
    }
    cout<<"max="<<a[w];
    return 0;
}

比较懒,就不上二维数组了(反正也没耐心看

二维数组求方案数:

#include<iostream>
using namespace std;
int a[100000],b[100000];
int n,wi,ci,w;
int main()
{
    cin>>n>>w;
    a[0]=1;
    for(int i=1;i<=n;i++)
        cin>>b[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=b[i];j<=w;j++)
        {
            a[j]=a[j]+a[j-b[i]];
        }
    }
    cout<<a[w];
    return 0;
}

多重循环:

#include<iostream>
using namespace std;
int f[200000],n,b[100000],c[100000],v,d[100000];
int max(int x,int y)
{
    if(x>y) return x;
    else return y;
}
int main()
{
    cin>>n>>v;
    for(int i=1;i<=n;i++)
    {
        cin>>b[i]>>c[i]>>d[i];
//        if(d[i]==0) d[i]=v;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=v;j>=b[i];j--)
        {
            for(int k=0;k<=d[i];k++)
                if(j>=k*b[i])
                    f[j]=max(f[j],f[j-b[i]*k]+c[i]*k);
        }
    }
    cout<<f[v];
    return 0;
}

然后多重背包的方案数和完全背包的方案数一样

ps:强调几个重点吧

1.用动态数组的时候一定要倒着循环,很重要

2.如果一定要用二维数组实现的话别忘了状态转移方程里01背包是i-1,完全背包是i本身,很蠢但是我错了好几次

posted @ 2022-09-25 19:55  董苏铭  阅读(19)  评论(0编辑  收藏  举报