背包问题2

纵饮孤独 提交于 2020-02-22 04:54:46

1268:【例9.12】完全背包问题

时间限制: 1000 ms 内存限制: 65536 KB
提交数: 10068 通过数: 5384

【题目描述】
设有nn种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为MM,今从nn种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于MM,而价值的和为最大。

【输入】
第一行:两个整数,MM(背包容量,M≤200M≤200)和NN(物品数量,N≤30N≤30);

第2…N+12…N+1行:每行二个整数Wi,CiWi,Ci,表示每个物品的重量和价值。

【输出】
仅一行,一个数,表示最大总价值。

【输入样例】
10 4
2 1
3 3
4 5
7 9【输出样例】
max=12
与01背包问题不同的是可以用无限次
将第二次遍历正序遍历的好处是可以将之前的结果累积起来,已达到多次使用的效果 即 当一个数是之前的一个数的两倍时他所累积的结果也是之前的两倍。


#include <iostream>
using namespace std;
int f[35][305];
int main()
{
    int m,n;
    cin>>m>>n;
    int w[35],c[35];
    for(int i=1;i<=n;i++)
    {
        cin>>w[i]>>c[i];
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
    {
        if(j<w[i]) f[i][j]=f[i-1][j];
        else f[i][j]=max(f[i-1][j],f[i][j-w[i]]+c[i]);
    }
    cout<<"max="<<f[n][m]<<endl;
}

 

同理换成一维数组也是一样的。
多重背包问题
1269:【例9.13】庆功会

时间限制: 1000 ms 内存限制: 65536 KB
提交数: 7906 通过数: 4509

【题目描述】
为了庆贺班级在校运动会上取得全校第一名成绩,班主任决定开一场庆功会,为此拨款购买奖品犒劳运动员。期望拨款金额能购买最大价值的奖品,可以补充他们的精力和体力。

【输入】
第一行二个数n(n≤500),m(m≤6000),其中n代表希望购买的奖品的种数,m表示拨款金额。

接下来n行,每行3个数,v、w、s,分别表示第I种奖品的价格、价值(价格与价值是不同的概念)和能购买的最大数量(买0件到s件均可),其中v≤100,w≤1000,s≤10。

【输出】
一行:一个数,表示此次购买能获得的最大的价值(注意!不是价格)。

【输入样例】
5 1000
80 20 4
40 50 9
30 50 7
40 30 6
20 20 1
【输出样例】
1040

#include <iostream>
using namespace std;
int f[6005];
int main()
{
    int m,n;
    cin>>n>>m;
    int v[505];
    int w[505],c[505];
    for(int i=1;i<=n;i++)
    {
        cin>>w[i]>>c[i]>>v[i];
    }
    for(int i=1;i<=n;i++)
        for(int j=m;j>=0;j--)
    {
       for(int k=0;k<=v[i];k++)
       {
           if(j>=k*w[i]) f[j]=max(f[j-k*w[i]]+k*c[i],f[j]);
           else break;
       }
    }
    cout<<f[m]<<endl;
}

 


优化方案,可以用二进制数1 2 4等数来组合表示买多件的情况。

#include <iostream>
using namespace std;
int main()
{
    int n,m;
    cin>>n>>m;
    int a[1000];
    int b[1000];
    int f[6000]={0};
    int w,v,p;
    int k=0;
    for(int i=1;i<=n;i++)
    {
        cin>>w>>v>>p;
        int t=1;
        int s=p;
        while(s>t)
        {
            a[++k]=w*t;
            b[k]=v*t;
            s=s-t;
            t=t*2;
        }
        a[++k]=s*w;
        b[k]=v*s;
    }
    for(int i=1;i<=k;i++)
    {
        for(int j=m;j>=a[i];j--)
        {
            f[j]=max(f[j],f[j-a[i]]+b[i]);
        }
    }
    cout<<f[m]<<endl;
    return 0;
}

这种方法使矩阵上每一个点的利用率更高从而减少了矩阵大小从而减少了运算次数。
即由
0001111111
000002333
000000246
变成了
000011111
111122233
22233344
22255667
大概就是这个样子,原来未利用的点也被利用了,矩阵变得更紧凑。
混合背包问题
1270:【例9.14】混合背包

时间限制: 1000 ms 内存限制: 65536 KB
提交数: 5353 通过数: 3182

【题目描述】
一个旅行者有一个最多能装V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,…,WnW1,W2,…,Wn,它们的价值分别为C1,C2,…,CnC1,C2,…,Cn。有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

【输入】
第一行:二个整数,M(背包容量,M≤200),N(物品数量,N≤30);

第2…N+1行:每行三个整数Wi,Ci,PiWi,Ci,Pi,前两个整数分别表示每个物品的重量,价值,第三个整数若为0,则说明此物品可以购买无数件,若为其他数字,则为此物品可购买的最多件数(PiPi)。

【输出】
仅一行,一个数,表示最大总价值。

【输入样例】
10 3
2 1 0
3 3 1
4 5 4【输出样例】
11
把前面几种情况组合一下即可。

#include <iostream>
using namespace std;
int f[205];
int main()
{
   int m;
   int n;
   int w[35],c[35];
   int p[35];
   cin>>m>>n;
   for(int i=1;i<=n;i++)
   {
       cin>>w[i]>>c[i]>>p[i];
   }
   for(int i=1;i<=n;i++)
   {
   if(p[i]==0)
   {
       for(int j=w[i];j<=m;j++)
       {
           f[j]=max(f[j],f[j-w[i]]+c[i]);
       }
   }
   else
   {
       for(int j=1;j<=p[i];j++)
        for(int k=m;k>=w[i];k--)
       {
           f[k]=max(f[k-w[i]]+c[i],f[k]);
       }
   }
   }
   cout<<f[m]<<endl;
    return 0;
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!