动态规划专题二 - 01背包及衍生背包问题

动态规划专题学习http://t.csdn.cn/HGc4W

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

本篇代码均以C[i]代表容量,w[i]代表权值,s[i]可选择次数

1267:【例9.11】01背包问题

没什么好讲的,根据专题一的动态规划基本模型的方式进行分析自然而然能够推出式子,以及01背包的模板也十分简单易懂,不多赘述

#include
using namespace std;
#define N 35
#define M 250
int dp[N][M], w[N], c[N];//dp[i][j]:在前i个物品中选择物品放入大小为j的背包能获得的最大价值 
int main()
{
    int m, n;
    cin >> m >> n;
    for(int i = 1; i <= n; ++i)
        cin >> w[i] >> c[i];
    for(int i = 1; i <= n; ++i)
        for(int j = 0; j <= m; ++j)
        {
            if(j >= w[i])
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]]+c[i]);
            else
                dp[i][j] = dp[i-1][j];
        }
    cout << dp[n][m];
    return 0;
}

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

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

#include
using namespace std;
#define N 35
#define M 250
int dp[N][M], w[N], c[N];//dp[i][j]:在前i个物品中选择物品放入大小为j的背包能获得的最大价值 
int main()
{
    int m, n;
    cin >> m >> n;
    for(int i = 1; i <= n; ++i)
        cin >> w[i] >> c[i];
    for(int i = 1; i <= n; ++i)
        for(int j = 0; j <= m; ++j)
        {
            if(j >= w[i])
                dp[i][j] = max(dp[i-1][j], dp[i][j-w[i]]+c[i]);
            else
                dp[i][j] = dp[i-1][j];
        }
    cout << dp[n][m];
    return 0;
}

唯一不同点在于

   dp[i][j] = max(dp[i-1][j], dp[i][j-w[i]]+c[i]);

区别在哪呢?

01背包要求的是只能装一个那么它的转移自然是从它的前i - 1个物品转移过来(即对于i物品只有选一个和不选俩种情况),但完全背包对于i个物品可以重复选择,那么它的转移状态自然是从前i个物品转移过来

虽然代码相差不大,但结果却大相径庭,因为对于01情况dp[i][j]只有dp[i - 1][j] 和dp[i - 1][j-w[i]]+c[i]俩种结果可以选择

而我们不难发现对于完全背包问题只要背包容量够大

 dp[i][j] = max(dp[i-1][j], dp[i][j-w[i]]+c[i]);

dp[i][j]会处于一个自加的状态

1269:【例9.13】庆功会

ybt 1269:【例9.13】庆功会

多重背包问题

1269:【例9.13】庆功会


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

【题目描述】

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

【输入】

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

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

【输出】

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

【输入样例】

5 1000
80 20 4
40 50 9
30 50 7
40 30 6
20 20 1

【输出样例】

1040

 

1270:【例9.14】混合背包

【题目描述】

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

【输入】

第一行:二个整数,M(背包容量,M<=200),N(物品数量,N<=30);

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

【输出】

仅一行,一个数,表示最大总价值。

【输入样例】

10  3
2  1  0
3  3  1
4  5  4

【输出样例】

11

【提示】

选第一件物品1件和第三件物品2件。

对于多重背包,可以视为代入完全背包思想的01背包

即如果第 i 项价格 价值 总量 为 A B C

可视为C 个 价格 为 A 价值为 B的物品

== >> 

原先多重背包

1 10 3

转换0-1

1 10

1 10 

1 10

那么对于第i项我们有不选 和 选 K 项的情况

选 K 项的前提为 K * C[i] K项的容量小于当前背包可使用的容量

   for(int i = 1; i <= n; i++)
        for(int j = 0; j <= m; j++)
            for(int k = 0;k <= s[i] && k * c[i] <= j;k++)

状态转移

对于第i件物品选K项(K可以为0)的情况也是通过其前i - 1项转移过来

但是对于第i件物品选1项或者2项和对其选3项的结果不存在绝对影响(可能是可以选3项i物品,但是其收益不如只选2项来的好)

因此它的转移有别于01和完全,并且和他们有相似点。

       dp[i][j] = max(dp[i][j], dp[i-1][j-k * c[i]] + w[i] * k);

AC代码

#include
using namespace std;
#define N 510
#define M 6100
int dp[N][M], w[N], c[N],s[N];//dp[i][j]:在前i个物品中选择物品放入大小为j的背包能获得的最大价值 
int main()
{
    int n,m;
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
        cin >> c[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 * c[i] <= j;k++)
                 dp[i][j] = max(dp[i][j], dp[i - 1][j-k * c[i]] + w[i] * k);
    cout << dp[n][m];
    return 0;
}

1270:【例9.14】混合背包 

ybt 1270:【例9.14】混合背包

1270:【例9.14】混合背包


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

【题目描述】

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

【输入】

第一行:二个整数,M(背包容量,M<=200),N(物品数量,N<=30);

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

【输出】

仅一行,一个数,表示最大总价值。

【输入样例】

10  3
2  1  0
3  3  1
4  5  4

【输出样例】

11

【提示】

选第一件物品1件和第三件物品2件。

提交 统计信息 提交记录

 

 可以转换成多重背包问题

#include
using namespace std;
#define N 510
#define M 6100
int dp[N][M], w[N], c[N],s[N];//dp[i][j]:在前i个物品中选择物品放入大小为j的背包能获得的最大价值 
int main()
{
    int n,m;
    cin >> m >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> c[i] >> w[i]  >> s[i];
        	if(s[i] == 0)//如果第i物品可以取无限个,实际最多可以取m/w[i]个 
			s[i] = m / c[i];
    }
    for(int i = 1; i <= n; i++)
        for(int j = 0; j <= m; j++)
            for(int k = 0;k <= s[i] && k * c[i] <= j;k++)
                 dp[i][j] = max(dp[i][j], dp[i - 1][j-k * c[i]] + w[i] * k);
    cout << dp[n][m];
    return 0;
}

1272:【例9.16】分组背包

1272:【例9.16】分组背包


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

【题目描述】

一个旅行者有一个最多能装V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn的价值分别为C1,C2,...,Cn。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

【输入】

第一行:三个整数,V(背包容量,V≤200),N(物品数量,N≤30)和T(最大组号,T≤10);

第2..N+1行:每行三个整数Wi,Ci,P,表示每个物品的重量,价值,所属组号。

【输出】

仅一行,一个数,表示最大总价值。

【输入样例】

10 6 3
2 1 1
3 3 1
4 8 2
6 9 2
2 8 3
3 9 3

【输出样例】

20

提交 统计信息 提交记录

#include
using namespace std;
const int N = 35;
const int T = 15;
const int V = 350;
int dp[T][V],c[N],w[N];//前 T 组V容量时最大收益
vectorg[T];
int main()
{
    int n,t,v,p;
    cin >> v >> n >> t;
    for(int i = 1;i <= n;i++)
    {
        cin >> w[i] >> c[i] >> p;
        g[p].emplace_back(i);
    }

    for(int i = 1;i <= t;i++)
    {
        for(int j = 0;j <= v;j++)
        {
            dp[i][j] = dp[i - 1][j];
            for(int k = 0;k < g[i].size();k++)
            {//枚举每一组的背包物品
                int x = g[i][k];
                if(w[x] <= j)
                dp[i][j] = max(dp[i][j],dp[i - 1][j - w[x]] + c[x]);
            }
        }
    }
    cout << dp[t][v] << endl;
    return 0;
}

 

你可能感兴趣的:(动态规划,算法,c++)