【背包问题】思路及模板代码

0-1背包问题-每件物品最多只可以使用一次

题目背景

【背包问题】思路及模板代码_第1张图片

思路

【背包问题】思路及模板代码_第2张图片
【背包问题】思路及模板代码_第3张图片

模板代码

#include
#include
using namespace std;
const int N=1010;
int f[N],n,m;
int v[N],w[N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d%d",&v[i],&w[i]);
    for(int i=1;i<=n;i++)
        for(int j=m;j>=v[i];j--)
            f[j]=max(f[j],f[j-v[i]]+w[i]);
    printf("%d",f[m]);
    return 0;
}

完全背包问题-每件物品可以使用无数次

题目背景

【背包问题】思路及模板代码_第4张图片

思路

【背包问题】思路及模板代码_第5张图片
【背包问题】思路及模板代码_第6张图片

模板代码

#include
using namespace std;
const int N=1010;
int f[N];
int n,m;
int v[N],w[N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d%d",&v[i],&w[i]);
    for(int i=1;i<=n;i++)
        for(int j=v[i];j<=m;j++)  //为什么这里的循环是正序?因为这里省掉的本来的就是第i层的数据,不是原本第i-1层的
            f[j]=max(f[j],f[j-v[i]]+w[i]);
    printf("%d",f[m]);
    return 0;
}

多重背包问题1-朴素枚举

题目背景

【背包问题】思路及模板代码_第7张图片

思路

直接单纯用二维数组硬算,枚举每种情况

模板代码

#include
#include
using namespace std;
const int N=110;
int n,m,s[N],v[N],w[N];
int f[N][N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d%d%d",&v[i],&w[i],&s[i]);
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;k<=s[i]&&k*v[i]<=j;k++)
                f[i][j]=max(f[i][j],f[i-1][j-v[i]*k]+w[i]*k);
    printf("%d",f[n][m]);
    return 0;
}

【背包问题】思路及模板代码_第8张图片


多重背包问题2-二进制优化

题目背景

【背包问题】思路及模板代码_第9张图片

思路

把任何一个数 N N N,利用二进制原理,拆分成 l o g N logN logN2的次方的数一个缺的补数,由这些数,可以自由组合,组合成1~N之间的任何数。
这样,枚举次数就从 N N N降低到 l o g N logN logN,也能等价的枚举出所有情况。
【背包问题】思路及模板代码_第10张图片
【背包问题】思路及模板代码_第11张图片

模板代码

#include
#include
using namespace std;
const int N=12010,M=2010;
int v[N],w[N],s[N];
int n,m,cnt;
int f[M];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        int a,b,sum;
        scanf("%d%d%d",&a,&b,&sum);//a是体积,b是价值,s是数量
        int k=1;
        while(k<=sum)             //二进制优化
        {
            cnt++;
            v[cnt]=a*k;
            w[cnt]=b*k;
            s[cnt]=k;
            sum-=k;
            k*=2;
        }
        if(sum>0)     //把最后缺的补到最后就行
        {
            cnt++;
            v[cnt]=a*sum;
            w[cnt]=b*sum;
            s[cnt]=sum;
        }
    }
    n=cnt;
    for(int i=1;i<=n;i++)                  //转化为0-1背包问题求解
        for(int j=m;j>=v[i];j--)
            f[j]=max(f[j],f[j-v[i]]+w[i]);
    printf("%d",f[m]);
    return 0;
}

分组背包问题-每组中最多只能选一个物品

题目背景

【背包问题】思路及模板代码_第12张图片

思路

【背包问题】思路及模板代码_第13张图片

模板代码

#include
using namespace std;
const int N=110;
int v[N][N],w[N][N],s[N];
int n,m;
int f[N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&s[i]);
        for(int j=1;j<=s[i];j++)
            scanf("%d%d",&v[i][j],&w[i][j]);
    }
    for(int i=1;i<=n;i++)
        for(int j=m;j>0;j--)
            for(int k=1;k<=s[i];k++)  //遍历每一组的情况
                if(v[i][k]<=j)
                    f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);
    printf("%d",f[m]);
    return 0;
}

你可能感兴趣的:(code,刷题,总结&记录,#,基础算法模板总结,动态规划,算法,背包问题)