动态规划之背包问题

无限背包

一个在旅途中的长者有一个最多能装M公斤的背包;

现在有n种物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn;

输入n、m以及各种物品的重量和价值,求旅行者能获得最大总价值。

输入:

3 16
5 4
4 3
6 6

输出:

12

代码与01背包几乎一样,只是枚举的顺序不同而已。

01背包枚举容量时,从大到小,避免一个物品被选择多次;

无限背包枚举容量时,从小到大,允许一件物品没做选择多次。

#include <stdio.h>
int n, m, i, j, k, w, v, f[105];
int main(){
    freopen("wxbag.in", "r", stdin);
    scanf("%d%d", &n, &m);
    for(i=1; i<=n; i++){
        scanf("%d%d", &w, &v);
        for(j=w; j<=m; j++){
            if(f[j-w] + v > f[j]){
                f[j] = f[j-w] + v;
            }
        }
    }
    printf("%d\n", f[m]);
    return 0;
}

多重背包

一个在旅途中的长者有一个最多能装M公斤的背包;

现在有n种物品,它们的重量分别是W1,W2,...,Wn,价值分别为V1,V2,...,Vn,数量分别为C1,C2,...,Cn;

输入n、m以及各种物品的重量、价值和数量,求旅行者能获得最大总价值。

输入:

3 16
5 4 2
4 3 5
6 6 1

输出:

12

多重背包,是指一个物品,可以选择多次;解法可以是将一件物品拆成多件物品。

如一件物品可以选择5次,那么我们可以看成是有5件那样的物品,做5次01背包即可。

#include <stdio.h>
int n, m, i, j, k, w, v, c, f[105];
int main(){
    freopen("dcbag.in", "r", stdin);
    scanf("%d%d", &n, &m);
    for(i=1; i<=n; i++){
        scanf("%d%d%d", &w, &v, &c);
        while(c--){
            for(j=m; j>=w; j--){
                if(f[j-w] + v > f[j]){
                    f[j] = f[j-w] + v;
                }
            }
        }
    }
    printf("%d\n", f[m]);
    return 0;
}

混合背包

有的物品只能选1次,有的物品可以选择多次,有的物品可以选择很多次……混合在一起,就是混合背包。

如多重背包中,物品的数量c很大,那就好超时了;数量很大时,应转成无限背包去做。

#include <stdio.h>
int n, m, i, j, k, w, v, c, f[105];
int main(){
    freopen("dcbag.in", "r", stdin);
    scanf("%d%d", &n, &m);
    for(i=1; i<=n; i++){
        scanf("%d%d%d", &w, &v, &c);
        if(c*w >= m){
            for(j=w; j<=m; j++){
                if(f[j-w] + v > f[j]){
                    f[j] = f[j-w] + v;
                }
            }
        }
        else{
            while(c--){
                for(j=m; j>=w; j--){
                    if(f[j-w] + v > f[j]){
                        f[j] = f[j-w] + v;
                    }
                }
            }
        }
    }
    printf("%d\n", f[m]);
    return 0;
}

练习题

1 -- [C++一本通-动态规划]例9.12 完全背包

题目描述

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

输入

第1行:两个整数,m(背包容量,m<=200)和n(物品数量,n<=30);

第2至n+1行:每行两个整数Wi,Ci,表示每个物品的重量和价值。

输出

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

样例输入

10 4
2 1
3 3
4 5
7 9

样例输出

max=12

参考代码

#include<bits/stdc++.h>
using namespace std;
const int qwq = 3000;
int m,n;
int w[qwq],v[qwq];
int dp[qwq][qwq];
int main() {
	cin>>m>>n;
	for(int i = 1; i <= n; i++) {
		cin>>w[i]>>v[i];
	}
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) {
			if(j < w[i]) {
				dp[i][j] = dp[i-1][j];
			} else {
				if(dp[i - 1][j] > dp[i][j - w[i]] + v[i]) {
					dp[i][j] = dp[i - 1][j];
				} else {
					dp[i][j] = dp[i][j - w[i]] + v[i];
				}
			}
		}
	}
	cout<<"max="<<dp[n][m];
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值