背包问题

01背包问题

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

第 ii 件物品的体积是 vivi,价值是 wiwi。

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

输入格式

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

接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 件物品的体积和价值。

输出格式

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

数据范围

0<N,V10000<N,V≤1000
0<vi,wi10000<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

8


//普通01背包 
#include<bits/stdc++.h>
using namespace std;
int dp[1001][1001];
int main()
{
    int n,V;
    cin>>n>>V;
    int v,w;
    for(int i=1;i<=n;i++)
    {
        cin>>v>>w;
        for(int j=1;j<=V;j++)
        {
            dp[i][j]=dp[i-1][j];
            if(j>=v)
                dp[i][j]=max(dp[i][j],dp[i-1][j-v]+w);
        }
    }
    printf("%d",dp[n][V]);
    return 0;
}

//滚动数组优化01背包(递推式只与上一个状态有关) 
#include<bits/stdc++.h>
using namespace std;
int dp[2][1001];
int main()
{
    int n,V;
    cin>>n>>V;
    int v,w;
    for(int i=1;i<=n;i++)
    {
        cin>>v>>w;
        for(int j=1;j<=V;j++)
        {
            dp[i&1][j]=dp[(i-1)&1][j];
            if(j>=v)
                dp[i&1][j]=max(dp[i&1][j],dp[(i-1)&1][j-v]+w);
        }
    }
    printf("%d",dp[n&1][V]);
    return 0;
}

//一维数组优化01背包(递推式只与上一个状态有关)
#include<bits/stdc++.h>
using namespace std;
int dp[1001];
int main()
{
    int n,V;
    cin>>n>>V;
    int v,w;
    for(int i=1;i<=n;i++)
    {
        cin>>v>>w;
        for(int j=V;j>=v;j--)//此处要倒序遍历,保证遍历每一个dp数组时用到的是上一个dp数组的值 
            dp[j]=max(dp[j],dp[j-v]+w);
    }
    printf("%d",dp[V]);
    return 0;
}

 

 

 

完全背包问题

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

第 ii 种物品的体积是 vivi,价值是 wiwi。

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

输入格式

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

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

输出格式

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

数据范围

0<N,V10000<N,V≤1000
0<vi,wi10000<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

10

//普通完全背包 (只有一个语句与01背包不同,就是完全背包只要空间足够可以无限次选择) 
#include<bits/stdc++.h>
using namespace std;
int dp[1001][1001];
int main()
{
    int n,V;
    cin>>n>>V;
    int v,w;
    for(int i=1;i<=n;i++)
    {
        cin>>v>>w;
        for(int j=1;j<=V;j++)
        {
            dp[i][j]=dp[i-1][j];
            if(j>=v)
                dp[i][j]=max(dp[i][j],dp[i][j-v]+w);
        }
    }
    printf("%d",dp[n][V]);
    return 0;
}

//滚动数组优化完全背包(递推式只与上一个状态有关) 
#include<bits/stdc++.h>
using namespace std;
int dp[2][1001];
int main()
{
    int n,V;
    cin>>n>>V;
    int v,w;
    for(int i=1;i<=n;i++)
    {
        cin>>v>>w;
        for(int j=1;j<=V;j++)
        {
            dp[i&1][j]=dp[(i-1)&1][j];
            if(j>=v)
                dp[i&1][j]=max(dp[i&1][j],dp[i&1][j-v]+w);
        }
    }
    printf("%d",dp[n&1][V]);
    return 0;
}

//一维数组优化完全背包(递推式只与上一个状态有关)
#include<bits/stdc++.h>
using namespace std;
int dp[1001];
int main()
{
    int n,V;
    cin>>n>>V;
    int v,w;
    for(int i=1;i<=n;i++)
    {
        cin>>v>>w;
        for(int j=v;j<=V;j++)//此处要正序遍历,遍历每一个dp数组时用到的可以是本次dp数组的值(与01背包不完全相同) 
            dp[j]=max(dp[j],dp[j-v]+w);
    }
    printf("%d",dp[V]);
    return 0;
}



多重背包问题

有 NN 种物品和一个容量是 VV 的背包。


第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi。


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


输入格式


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


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


输出格式


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


数据范围


0<N,V1000<N,V≤100
0<vi,wi,si1000<vi,wi,si≤100


输入样例


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

输出样例:


10
 
//普通多重背包 
#include<bits/stdc++.h>
using namespace std;
int dp[101][101];
int main()
{
    int n,V;
    cin>>n>>V;
    int v,w,s;
    for(int i=1;i<=n;i++)
    {
        cin>>v>>w>>s;
        for(int j=1;j<=V;j++)
        {
            dp[i][j]=dp[i-1][j];
            for(int k=1;k<=s&&k*v<=j;k++)//别忘了此处选择数目不得超过s 
                dp[i][j]=max(dp[i][j],dp[i-1][j-k*v]+k*w);
        }
    }
    printf("%d",dp[n][V]);
    return 0;
}

//滚动数组优化多重背包(递推式只与上一个状态有关) 
#include<bits/stdc++.h>
using namespace std;
int dp[2][101];
int main()
{
    int n,V;
    cin>>n>>V;
    int v,w,s;
    for(int i=1;i<=n;i++)
    {
        cin>>v>>w>>s;
        for(int j=1;j<=V;j++)
        {
            dp[i&1][j]=dp[(i-1)&1][j];
            for(int k=1;k<=s&&k*v<=j;k++)
                dp[i&1][j]=max(dp[i&1][j],dp[(i-1)&1][j-k*v]+k*w);
        }
    }
    printf("%d",dp[n&1][V]);
    return 0;
}

//一维数组优化多重背包(递推式只与上一个状态有关)
#include<bits/stdc++.h>
using namespace std;
int dp[101];
int main()
{
    int n,V;
    cin>>n>>V;
    int v,w,s;
    for(int i=1;i<=n;i++)
    {
        cin>>v>>w>>s;
        for(int j=V;j>=v;j--)//此处要倒序序遍历(与01背包原理相同) 
        for(int k=1;k<=s&&k*v<=j;k++)
            dp[j]=max(dp[j],dp[j-k*v]+k*w);
    }
    printf("%d",dp[V]);
    return 0;
}

 多重背包转化为01背包处理(数据有所加强,若仍使用普通多重背包则无法通过)

 

有 NN 种物品和一个容量是 VV 的背包。

第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi。

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

输入格式

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

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

输出格式

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

数据范围

0<N10000<N≤1000
0<V20000<V≤2000
0<vi,wi,si20000<vi,wi,si≤2000

提示:

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

输入样例

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

输出样例:

10


 

//滚动数组优化多重背包(数据有所加强) 
#include<bits/stdc++.h>
using namespace std;
int dp[2][2010];
int v[12010],w[12010];
int main()
{
    int n,V;
    cin>>n>>V;
    int v1,w1,s1;
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        cin>>v1>>w1>>s1;
        for(int j=1;j<=s1;j*=2)
            ++cnt,v[cnt]=j*v1,w[cnt]=j*w1,s1-=j;
        if(s1>0)
            ++cnt,v[cnt]=s1*v1,w[cnt]=s1*w1;
    }
    for(int i=1;i<=cnt;i++)
        for(int j=1;j<=V;j++)
        {
            dp[i&1][j]=dp[(i-1)&1][j];
            if(j>=v[i])
                dp[i&1][j]=max(dp[i&1][j],dp[(i-1)&1][j-v[i]]+w[i]);
        }
    printf("%d",dp[cnt&1][V]);
    return 0;
}

//一维数组优化多重背包(数据有所加强) 
#include<bits/stdc++.h>
using namespace std;
int dp[2010];
int v[12010],w[12010];
int main()
{
    int n,V;
    cin>>n>>V;
    int v1,w1,s1;
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        cin>>v1>>w1>>s1;
        for(int j=1;j<=s1;j*=2)
            ++cnt,v[cnt]=j*v1,w[cnt]=j*w1,s1-=j;
        if(s1>0)
            ++cnt,v[cnt]=s1*v1,w[cnt]=s1*w1;
    }
    for(int i=1;i<=cnt;i++)
        for(int j=V;j>=v[i];j--)
        {
            dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
        }
    printf("%d",dp[V]);
    return 0;
}

 

 

 

 

分组背包问题

有 NN 组物品和一个容量是 VV 的背包。

每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 vijvij,价值是 wijwij,其中 ii 是组号,jj 是组内编号。

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

输出最大价值。

输入格式

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

接下来有 NN 组数据:

  • 每组数据第一行有一个整数 SiSi,表示第 ii 个物品组的物品数量;
  • 每组数据接下来有 SiSi 行,每行有两个整数 vij,wijvij,wij,用空格隔开,分别表示第 ii 个物品组的第 jj 个物品的体积和价值;

输出格式

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

数据范围

0<N,V1000<N,V≤100
0<Si1000<Si≤100
0<vij,wij1000<vij,wij≤100

输入样例

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

输出样例:

8

//普通分组背包(在01背包上面加一层背包组数的循环即可) 
#include<bits/stdc++.h>
using namespace std;
int dp[101][101];
int main()
{
    int n,V;
    cin>>n>>V;
    int v,w,s;
    for(int i=1;i<=n;i++)
    {
        cin>>s;
        for(int j=1;j<=s;j++)
        {
            cin>>v>>w;
            for(int k=1;k<=V;k++)
                {
                    if(j==1)//要保证对于每一个dp[i][k]只被赋值一次 
                        dp[i][k]=dp[i-1][k];
                    if(k>=v)
                        dp[i][k]=max(dp[i][k],dp[i-1][k-v]+w);
                }
        }
    }
    printf("%d",dp[n][V]);
    return 0;
}

//滚动数组优化分组背包(递推式只与上一个状态有关) 
#include<bits/stdc++.h>
using namespace std;
int dp[2][101];
int main()
{
    int n,V;
    cin>>n>>V;
    int v,w,s;
    for(int i=1;i<=n;i++)
    {
        cin>>s;
        for(int j=1;j<=s;j++)
        {
            cin>>v>>w;
            for(int k=1;k<=V;k++)
                {
                    if(j==1)
                        dp[i&1][k]=dp[(i-1)&1][k];
                    if(k>=v)
                        dp[i&1][k]=max(dp[i&1][k],dp[(i-1)&1][k-v]+w);
                }
        }
    }
    printf("%d",dp[n&1][V]);
    return 0;
}

 

 

 

posted @ 2021-05-02 13:31  AC--Dream  阅读(87)  评论(0编辑  收藏  举报