ACM__01背包,完全背包,多重背包

今天写题的时候碰到了一道完全背包题,可是没有看出来,乱写了一通,浪费了一个晚上,顺便复习一下背包的知识

01背包

每种物品只能选择一次或者不选,求背包容量内的最大价值

先给出状态转移方程:

f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);

解释一下:f[i][j]表示的是前i个物品中,背包容量为j时,得到的最大价值;如果在容量为j时选择不放第i个物品,那么f[i][j]=f[i-1][j],f[i-1][j]表示前一个物品在容量j时的状态值;如果在容量为j时选择放第i个物品,那么f[i][j]=f[i-1][j-w[i]]+v[i],f[i-1][j-w[i]]+v[i]表示前一个物品得到的状态加上第i个物品的价值;自然而然,f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);

下面是二维数组的代码,自己敲了一遍,加深印象

 1 #include<cstdio>
 2 int main()
 3 {
 4     int n,m,v[105],w[105],f[105][105];
 5     scanf("%d %d",&m,&n);
 6     for(int i=1;i<=n;i++)
 7         scanf("%d %d",&v[i],&w[i]);
 8     for(int i=1;i<=n;i++)
 9     {
10         for(int j=1;j<=m;j++)
11         {
12             if(w[i]<=j)
13             f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
14             else
15                 f[i][j]=f[i-1][j];
16         }
17     }
18     printf("%d",f[n][m]);
19     return 0;
20 }

还有一种是一维数组的方法,更能节省空间

 1 #include<cstdio>
 2 int main()
 3 {
 4     int n,m,v[105],w[105],f[105];
 5     scanf("%d %d",&m,&n);
 6     for(int i=1;i<=n;i++)
 7         scanf("%d %d",&v[i],&w[i]);
 8     for(int i=1;i<=n;i++)
 9     {
10         for(int j=m;j>=1;j--)
11         {
12             if(w[i]<=j)
13             f[j]=max(f[j],f[j-w[i]]+v[i]);
14         }
15     }
16     printf("%d",f[m]);
17     return 0;
18 }

里面第二个循环为什么要倒着来,遍历到第i个物品时,f[j]应该与第i-1个物品的状态比较,如果顺着来的话,f[j]则与第i个物品的状态进行了比较,这样会出事的;

完全背包

每种物品可以选无数次,求背包容量内的最大价值

状态转移方程为:f[j]=max(f[j],f[j-w[i]]+v[i]);

贴上代码:

 1 #include<cstdio>
 2 int main()
 3 {
 4     int n,m,v[105],w[105],f[105];
 5     scanf("%d %d",&m,&n);
 6     for(int i=1;i<=n;i++)
 7         scanf("%d %d",&v[i],&w[i]);
 8     for(int i=1;i<=n;i++)
 9     {
10         for(int j=w[i];j<=m;j++)
11         {
12             f[j]=max(f[j],f[j-w[i]]+v[i]);
13         }
14     }
15     printf("%d",f[m]);
16     return 0;
17 }

多重背包

每种物品能取有限次,求背包容量内的最大值

多重背包问题化作01背包问题解决,如果价值为v的物品有x个,则化成x个价值为v的物品;

#include<cstdio>
int main()
{
    int n,m,v[105],w[105],f[105];
    scanf("%d %d",&m,&n);
    for(int i=1; i<=n; i++)
        scanf("%d %d",&v[i],&w[i],&num[i]);
    int k=n+1;
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<num[i]; j++)
        {
            v[k]=v[i];
            w[k]=w[i];
            k++;
        }
    }
    for(int i=1; i<k; i++)
    {
        for(int j=m; j>=1; j--)
        {
            if(w[i]<=j)
                f[j]=max(f[j],f[j-w[i]]+v[i]);
        }
    }
    printf("%d",f[m]);
    return 0;
}

  再贴上今天折腾了一晚上的题:http://acm.sdibt.edu.cn/JudgeOnline/problem.php?id=2340

把数组改为全局变量竟然就A了,问了老谭,说这是,没有清零的原因,脑瓜子疼!

猜你喜欢

转载自www.cnblogs.com/LLLAIH/p/9665750.html
今日推荐