网络知识 娱乐 背包问题(基本全)

背包问题(基本全)

喔是宝藏UP🐖

这里写目录标题

  • 喔是宝藏UP🐖
  • AcWing 2. 01背包问题(基础)
    • 二维01[AC]
    • 优化思路:二维-->一维
    • 一维01[AC]
  • AcWing 3. 完全背包问题(基础)
    • 三维[TLE]
    • 优化思路:三for-->二for
    • 二维/一维[AC]【优化:与01背包相同】
  • AcWing 4. 多重背包问题(基础)
    • 三维[AC]--不能像完全背包的二维优化【原因】
  • AcWing 5. 多重背包问题 II (基础)
    • 优化思路:三维-->01背包问题【二维/一维】
    • 二维[AC]--数据范围变大--二进制优化
  • AcWing 9. 分组背包问题(基础)
    • 二维/一维[AC]【优化:与01背包相同】
  • AcWing 423. 采药(01背包模板)
    • 二维/一维[AC]【优化:与01背包相同】
  • AcWing 1024. 装箱问题(01背包模板)
    • 二维/一维[AC]【优化:与01背包相同】
  • AcWing 1022. 宠物小精灵之收服(二维费用的01背包)
    • 二维[AC]
  • AcWing 278. 数字组合(01背包问题求方案数)
    • 二维/一维[AC]【优化:与01背包相同】
  • AcWing 1023. 买书 (完全背包问题求方案数)--类似上一题
    • 二维/一维[AC]【优化:与01背包相同】
  • AcWing 1021. 货币系统(完全背包问题求方案数)
    • 二维[AC]【优化:与完全背包1相同】
      • 三for
      • 二for
    • 一维[AC]【优化:与01背包相同】
  • AcWing 532. 货币系统 (上一题拓展)
    • AC代码
  • AcWing 6. 多重背包问题 III(暂无)
  • AcWing 1019. 庆功会(多重背包1模板)
    • AC代码:可以二进制优化(略)
  • AcWing 7. 混合背包问题 (01,完全,多重)
    • 一维[AC]
  • AcWing 8. 二维费用的背包问题(二维费用的01背包)
    • 三维/二维【优化:与01背包相同】
  • AcWing 1020. 潜水员(二维费用的01背包+不少于的问题)
    • 三维(略)/二维
  • AcWing 1013. 机器分配 (分组背包+具体方案输出)
    • 二维[AC]
  • AcWing 426. 开心的金明 (01背包模板)
    • 二维/一维[AC]【优化:与01背包相同】
  • AcWing 10. 有依赖的背包问题(暂无)
  • AcWing 11. 背包问题求方案数 (最优选法的方案数)
    • 定义:恰好
    • 定义:不大于
  • AcWing 12. 背包问题求具体方案(字典序最小的具体方案输出)
    • 二维[AC]
  • AcWing 734. 能量石 (暂无)
  • AcWing 487. 金明的预算方案(暂无)

在这里插入图片描述

AcWing 2. 01背包问题(基础)

有 N 件物品和一个容量是 V的背包。每件物品只能使用一次。

第 i件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。

接下来有 N行,每行两个整数 vi,wi,用空格隔开,分别表示第 i件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围

0<N,V≤1000

0<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

8

二维01[AC]

#include
using namespace std;
const int N=1010;
int w[N],v[N],f[N][N];
int n,m;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
    
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            f[i][j]=f[i-1][j];
            if(j>=v[i])f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
        }
    }
    cout<<f[n][m]<<endl;
}

优化思路:二维–>一维

在这里插入图片描述

一维01[AC]

#include
using namespace std;

const int N=1010;
int n,m;
int v[N],w[N],f[N];
//f[i]:N 件物品,背包容量j下的最优解。
//删除第一维
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
    
    for(int i=1;i<=n;i++)
    {
        //m-->v[i]先计算大的,即f[i][j-v[i]]
        //v[i]-->m先计算小的,即f[i-1][j-v[i]]
        for(int j=m;j>=v[i];j--)
        {
            //f[i][j]=f[i-1][j];
            //f[j]=f[j]
            
            //if(j>=v[i])f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
            //f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
            
            //v[i]-->m
            //如果删除第一维:f[j]=max(f[j],f[j-v[i]]+w[i])
            //等价于f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);
            
            //m-->v[i]
            //如果删除第一维:f[j]=max(f[j],f[j-v[i]]+w[i])
            //等价于f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
            
            //原因:
            //eg:v[i]-->m先计算小的,i=1时,由于j-v[1]<j,所以f[j-v[1]]先计算,即f[j-v[1]]是f[1][j-v[i]]
            //在计算f[j]=max(f[j],f[j-v[i]]+w[i])时,用到的是f[1][j-v[1]]+w[i]
            //eg:m-->v[i]先计算大的,i=1时,由于j-v[1]<j,所以f[j]先计算,即f[j-v[1]]是f[0][j-v[i]]
            //在计算f[j]=max(f[j],f[j-v[i]]+w[i])时,用到的是f[0][j-v[i]]+w[i]
            
            f[j]=max(f[j],f[j-v[i]]+w[i]);
        }   
        
    }
    
    cout<<f[m]<<endl;
}

AcWing 3. 完全背包问题(基础)

有 N 种物品和一个容量是 V的背包,每种物品都有无限件可用。

第 i种物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 N行,每行两个整数 vi,wi,用空格隔开,分别表示第 i种物品的体积和价值。
输出格式

输出一个整数,表示最大价值。
数据范围

0<N,V≤1000

0<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

10
//01:f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
//完全:f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);

//01:f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);-->用到的是f[i-1][....]故从大到小循环即可
//完全:f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);-->用到的是f[i][....]故从小到大循环即可

//为什么可以2个for:
//因为            
// for(int j=1;j<=m;j++)
// {
//     for(int k=0;k*v[i]<=j;k++)
//     {
//         f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
//     }
// }
//可以转换

三维[TLE]

#include
using namespace std;
const int N=1010;
int w[N],v[N],f[N][N];
int n,m;

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            for(int k=0;k*v[i]<=j;k++)
            {
                f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
            }
            
        }
    }
    
    cout<<f[n][m]<<endl;
}

优化思路:三for–>二for

优化

二维/一维[AC]【优化:与01背包相同】

#include
using namespace std;
const int N=1010;
int w[N],v[N],f[N][N];
int n,m;

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            f[i][j]=f[i-1][j];
            if(j>=v[i])f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);
        }
    }
    
    cout<<f[n][m]<<endl;
}
#include
using namespace std;
const int N=1010;
int w[N],v[N],f[N];
int n,m;

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
    
    for(int i=1;i<=n;i++)
    {
        for(int j=v[i];j<=m;j++)
        {
            f[j]=max(f[j],f[j-v[i]]+w[i]);
            //f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);-->用到的是f[i][....]故从小到大循环即可
            //f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);-->用到的是f[i-1][....]故从大到小循环即可
        }
    }
    cout<<f[m]<<endl;
}

AcWing 4. 多重背包问题(基础)

有 N 种物品和一个容量是 V的背包。

第 i种物品最多有 si 件,每件体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。输出最大价值。
输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 N行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i种物品的体积、价值和数量。
输出格式

输出一个整数,表示最大价值。
数据范围

0<N,V≤100

0<vi,wi,si≤100

输入样例

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10
//为什么必须三个for:
//因为            //
//for(int k=0;k=k*v[i])
//    f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
//}
//无法转换

三维[AC]–不能像完全背包的二维优化【原因】

优化思路

#include
using namespace std;

const int N=110;
int n,m;
int v[N],w[N],s[N];
int f[N][N];
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>v[i]>>w[i]>>s[i];
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            for(int k=0;k<=s[i];k++)
            {
                if(j>=k*v[i])
                f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
            }
        }
    }
    
    cout<<f[n][m]<<endl;
}

AcWing 5. 多重背包问题 II (基础)

有 N 种物品和一个容量是 V的背包。

第 i种物品最多有 si 件,每件体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。输出最大价值。
输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 N行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i种物品的体积、价值和数量。
输出格式

输出一个整数,表示最大价值。
数据范围

0<N≤1000

0<V≤2000
0<vi,wi,si≤2000

提示:

本题考查多重背包的二进制优化方法。
输入样例

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10

优化思路:三维–>01背包问题【二维/一维】

优化

二维[AC]–数据范围变大–二进制优化

//做法:将10分成1,2,4,3
//        16    1,2,4,8,1
//将1,2,4,3,1,2,4,8,1分别变成一个新的物品,然后进行01背包
//原因:复杂度小,而且可以进行组合,变成需要的数量

#include
using namespace std;
const int N=1000*15;//1000*log 2000
int a,b,c,cnt;
int n,m;
int f[N];
int v[N],w[N],s[N];
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>a>>b>>c;
        int k=1;//代表捆绑之后的物品个数;
        while(c>=k)
        {
            cnt++;//cnt=[1,n]
            v[cnt]=k*a;
            w[cnt]=k*b;
            c=c-k;
            k=2*k;
        }
        if(c>0)
        {
            
            cnt++;//cnt=1
            v[cnt]=c*a;
            w[cnt]=c*b;
        }
    }
    
    
    int n1=cnt;//捆绑之后的商品数量
    for(int i=1;i<=n1;i++)
    {
        for(int j=m;j>=v[i];j--)
        {
            f[j]=max(f[j],f[j-v[i]]+w[i]);
        }
    }
    
    cout<<f[m]<<endl;
}

AcWing 9. 分组背包问题(基础)

有 N 组物品和一个容量是 V的背包。

每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 vij,价值是 wij,其中 i 是组号,j是组内编号。

求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。

输出最大价值。
输入格式

第一行有两个整数 N,V,用空格隔开,分别表示物品组数和背包容量。

接下来有 N组数据:
每组数据第一行有一个整数 Si,表示第 i个物品组的物品数量;每组数据接下来有 Si行,每行有两个整数 vij,wij,用空格隔开,分别表示第 i 个物品组的第 j 个物品的体积和价值;

输出格式
输出一个整数,表示最大价值。

数据范围
0<N,V≤100
0<Si≤100
0<vij,wij≤100

输入样例

3 5
2
1 2
2 4
1
3 4
1
4 5

输出样例:

8

二维/一维[AC]【优化:与01背包相同】

//为什么必须三个for:
//因为必须要用到k
#include
using namespace std;
const int N=110;
int n,m;
int s[N],v[N][N],w[N][N],f[N][N],dp[N];
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
        for(int j=1;j<=s[i];j++)
        cin>>v[i][j]>>w[i][j];
    }

    //二维
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            f[i][j]=f[i-1][j];//0
            for(int k=1;k<=s[i];k++)
            if(j>=v[i][k])
               f[i][j]=max(f[i][j],f[i-1][j-v[i][k]]+w[i][k]);//1.....s[i]
        }
    }
    cout<<f[n][m]<<endl;
    return 0;
}
//为什么必须三个for:
//因为必须要用到k
#include
using namespace std;
const int N=110;
int n,m;
int s[N],v[N][N],w[N][N],f[N][N],dp[N];
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
        for(int j=1;j<=s[i];j++)
        cin>>v[i][j]>>w[i][j];
    }
    //一维
    for(int i=1;i<=n;i++)
        for(int j=m;j>=0;j--)
            for(int k=0;k<=s[i];k++)
            if(j>=v[i][k])dp[j]=max(dp[j],dp[j-v[i][k]]+w[i][k]);
    
    cout<<dp[m]<<endl;
    return 0;
}

AcWing 423. 采药(01背包模板)

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。

为此,他想拜附近最有威望的医师为师。

医师为了判断他的资质,给他出了一个难题。

医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?
输入格式

输入文件的第一行有两个整数 T和 M,用一个空格隔开,T 代表总共能够用来采药的时间