物品数量N=5件
重量w分别是2 2 6 5 4
价值v分别是6 3 5 4 6
背包承重为M=10
背包内物品最大总和为15
5 10 2 2 6 5 4 6 3 5 4 6
15
“求价值最大和”,毋庸置疑,用动态规划。此类题目属于动态规划中的一个特殊类别——“背包问题”。
PS:背包问题可以分为三种——
设当前个数为i,当前最大背包容量为j,那么dp[i][j]表示“背包容量为j时,在前i个物品中选择的最大价值和”。有如下状态公式(设w为重量数组,v为价值数组):
解释状态公式:
// // Created by jt on 2020/8/26. // #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int N, M; cin >> N >> M; vector<int> w, v; for (int i = 0; i < N; ++i) { int a; cin >> a; w.push_back(a); } for (int i = 0; i < N; ++i) { int a; cin >> a; v.push_back(a); } vector<vector<int>> dp(N+1, vector<int>(M+1, 0)); for (int i = 1; i <= N; ++i) { for (int j = 1; j <= M; ++j) { dp[i][j] = j-w[i-1] >= 0 ? max(dp[i-1][j-w[i-1]]+v[i-1], dp[i-1][j]) : dp[i-1][j]; } } cout << dp[N][M] << endl; }
使用递归+记忆化数组import java.util.Scanner;public class Main { static int w[]; static int v[]; static int dp[]; public static void main(String[] args) { Scanner scanner=new Scanner(System.in); int N=scanner.nextInt(); w=new int[N]; v=new int[N]; int C=scanner.nextInt(); dp=new int[C+1]; for (int i = 0; i < N; i++) { w[i]=scanner.nextInt(); } for (int i = 0; i < N; i++) { v[i]=scanner.nextInt(); } for (int i = 0; i < N; i++) { //物品 for (int j = C; j >=w[i]; j--) { //容量 dp[j]=Math.max(dp[j],dp[j-w[i]]+v[i]); } } System.out.println(dp[C]); } }
import java.util.Scanner; public class Main { static int N; static int W; static int w[]; static int v[]; static int a[][]; static int dfs(int index,int C){ //C 表示当前容量 if(index>N)return 0; if(C<0)return 0; if(a[index][C]!=0)return a[index][C]; if(C-w[index]<0) { a[index][C]= dfs(index + 1, C); }else { a[index][C]= Math.max(v[index] + dfs(index + 1, C - w[index]), dfs(index + 1, C)); } return a[index][C]; } public static void main(String[] args) { Scanner reader=new Scanner(System.in); N= reader.nextInt(); W= reader.nextInt(); w=new int[N+1]; v=new int[N+1]; a=new int[N+1][W+1]; for (int i = 0; i < N; i++) { w[i]= reader.nextInt(); } for (int i = 0; i < N; i++) { v[i]= reader.nextInt(); } System.out.println(dfs(0,W)); } }
import java.util.*; public class Main { static int maxValue = 0; public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { int N = sc.nextInt(); int M = sc.nextInt(); int[] w = new int[N]; int[] v = new int[N]; for (int i = 0; i < N; i++) { w[i] = sc.nextInt(); } for (int i = 0; i < N; i++) { v[i] = sc.nextInt(); } dfs(w,v,M,0,N,0); System.out.println(maxValue); } } public static void dfs(int[] w, int[] v, int m, int start, int N,int value) { // 剪枝,当m<=0 不能装了,就不用挨个比较了 if (m <= 0) { return; } for (int i = start; i < N; i++) { // 如果背包容量还够,就装进去 if (m - w[i] >= 0) { value += v[i]; if (value > maxValue) { maxValue = value; } m = m - w[i]; // 在第一个装的基础上,看看后面的装不装 dfs(w,v,m,i+1,N,value); // 回溯,第一个不装,下一轮for循环就会考虑装不装第二个了 value -= v[i]; m += w[i]; } } } }
public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int N = sc.nextInt(); int M = sc.nextInt(); int[] w = new int[N]; for(int i = 0; i < N; i++) { w[i] = sc.nextInt(); } int[] v = new int[N]; for(int i = 0; i < N; i++) { v[i] = sc.nextInt(); } System.out.println(knapsack(M, N, w, v)); } public static int knapsack(int M, int N, int[] w, int[] v) { int[][] dp = new int[N+1][M+1]; for(int i = 1; i <= N; i++) { for(int j = 1; j <= M; j++) { if(j - w[i-1] < 0) { dp[i][j] = dp[i-1][j]; // 装不下 } else { dp[i][j] = Math.max(dp[i-1][j-w[i-1]] + v[i-1], dp[i-1][j]); // 装和不装 } } } return dp[N][M]; } }
const readline = require('readline') const rl = readline.createInterface({ input: process.stdin, output: process.stdout }) let lines = [] let p = new Promise((resolve, reject)=>{ rl.on('line', function(line){ lines.push(line) lines.length === 4 && resolve(lines) }) }) p.then(data => { let N = parseInt(lines[0]) // 物品数量 let M = parseInt(lines[1]) // 背包承重量 let w = lines[2].split(' ').map(x => parseInt(x)) // 重量数组 let v = lines[3].split(' ').map(x => parseInt(x)) // 价值价值数组 // 开始dp // dp中存放某重量对应的最大价值 // 状态转移方程 :dp[j] = Max{dp[j], dp[j - w[i]] + v[i]} // 等式左边dp[j] : j公斤重量对应的最大价值(待计算) // 等式右边dp[j] : j公斤重量对应的最大价值(之前计算的,不包含i物品) // dp[j - w[i]] + v[i] : 挑选i物品来凑j公斤时能得到的最大价值 let dp = new Array(M + 1).fill(0) for(let i = 0; i < N; i++){ for(let j = M; j >= w[i]; j--){ dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]) } } // 输出结果(打印) console.log(dp[M]) }, err => { throw err })牛客编程题中JS读取输入流与输出结果的方式
const readline = require('readline') const rl = readline.createInterface({ input: process.stdin, output: process.stdout }) // 输入缓存 let lines = [] let p = new Promise((resolve, reject)=>{ // 监听输入,遇到回车调用回调函数 // 回车前的输入流以字符串的形式存放在line中 rl.on('line', function(line){ lines.push(line) // ... // 判断输入是否结束, 若结束则调用resolve lines.length > 7 && resolve(lines) }) }) p.then(data => { // data是resolve回调中传入的lines // ... // 输出流,打印结果 console.log() }, err => { throw err })
import random thing_number = int(input()) weight = input() KG = input() KG_list = [int(i) for i in KG.split(" ") if i not in [""]] value = input() value_list = [int(i) for i in value.split(" ") if i not in [""]] value_max = 0 for i in range(thing_number): for j in range(50*thing_number*thing_number): value_all = 0 weight_all = 0 random_index = [] while True: index = random.choice(range(thing_number)) if index not in random_index: random_index.append(index) if len(random_index) == i + 1: break for r in random_index: weight_all += KG_list[r] value_all += value_list[r] if weight_all <= int(weight): if value_all > value_max: value_max = value_all print(value_max)
来个C++版本
#include <climits> #include <iostream> #include <vector> using namespace std; int main() { int N; int M; cin>>N; cin>>M; vector<int> w(N); vector<int> v(N); vector<int> f(M+1,0); for(int i=0;i<N;++i) cin>>w[i]; for(int i=0;i<N;++i) cin>>v[i]; for(int i=1;i<=N;++i){ int x = w[i-1]; for(int j=M;j>=x;--j){ f[j] = max(f[j],f[j-x]+v[i-1]); } } cout << f[M]<<endl; return 0; } // 64 位输出请用 printf("%lld")
#include <stdio.h> #include <stdlib.h> #define MAX(x, y) ((x)>(y))?(x):(y) typedef struct { int weight; int value; }Bagobj; int SolveBagProb(int N, int M, Bagobj *objlist); int SolveBagProbPlus(int N, int M, Bagobj *objlist); int SolveBagProbPlusPlus(int N, int M, Bagobj *objlist); int main() { //输入数据 int N = 0; int M = 0; //1. 物品的数量 scanf("%d", &N); scanf("%d", &M); Bagobj *objlist = (Bagobj *)malloc(sizeof(Bagobj)*N);//使用动态数组 for(int i=0; i<N; i++) { scanf("%d", &objlist[i].weight); } for(int i=0; i<N; i++) { scanf("%d", &objlist[i].value); } #if 1 //int res = SolveBagProb(N, M, objlist); //int res = SolveBagProbPlus(N, M, objlist); int res = SolveBagProbPlusPlus(N, M, objlist); printf("%d", res); #endif } //解决背包问题: //所需要的数据:物品种类N,背包承重M,每种物品的重量和价值(w,v) int SolveBagProb(int N, int M, Bagobj *objlist) { //初始化一个动态规划数组,dp[N][M+1],初始化其第一行。 //对于dp[i][j]而言:i是前i个物件,j是背包的承重(变)。 int dp[N][M+1]; for(int j=0; j<=M; j++) { //求价值,下面这处错误 //dp[0][j] = (j>=objlist[0].weight)?(objlist[0].weight):(0); dp[0][j] = (j>=(objlist[0].weight))?(objlist[0].value):(0); //printf("dp[0][%d] = %d\n",j, dp[0][j]); } //对下面每一行[1, N-1],求动态规划式子 int alt_full = 0; int alt_notfull = 0; for(int i=1; i<N; i++) { for(int j=0; j<=M; j++) { alt_full = dp[i-1][j]; int temp_weight = objlist[i].weight; if(j >= temp_weight) { //alt_notfull = dp[i-1][j-temp_weight]+temp_weight; alt_notfull = dp[i-1][j-temp_weight]+objlist[i].value; } else { alt_notfull = 0; } dp[i][j] = MAX(alt_full, alt_notfull); //printf("dp[%d][%d] = %d\n",i,j, dp[i][j]); } } return dp[N-1][M]; } int SolveBagProbPlus(int N, int M, Bagobj *objlist) { //初始化一个动态规划数组,dp[N][M+1],初始化其第一行。 //对于dp[i][j]而言:i是前i个物件,j是背包的承重(变)。 int dp[2][M+1]; for(int j=0; j<=M; j++) { //求价值,下面这处错误 //dp[0][j] = (j>=objlist[0].weight)?(objlist[0].weight):(0); dp[0][j] = (j>=(objlist[0].weight))?(objlist[0].value):(0); //printf("dp[0][%d] = %d\n",j, dp[0][j]); } //对下面每一行[1, N-1],求动态规划式子 int alt_full = 0; int alt_notfull = 0; for(int i=1; i<N; i++) { for(int j=0; j<=M; j++) { alt_full = dp[(i-1)&0x01][j]; int temp_weight = objlist[i].weight; if(j >= temp_weight) { //alt_notfull = dp[i-1][j-temp_weight]+temp_weight; alt_notfull = dp[(i-1)&0x01][j-temp_weight]+objlist[i].value; } else { alt_notfull = 0; } dp[i&0x01][j] = MAX(alt_full, alt_notfull); //printf("dp[%d][%d] = %d\n",i,j, dp[i][j]); } } return dp[(N-1)&0x01][M]; } int SolveBagProbPlusPlus(int N, int M, Bagobj *objlist) { //初始化一个动态规划数组,dp[N][M+1],初始化其第一行。 //对于dp[i][j]而言:i是前i个物件,j是背包的承重(变)。 int dp[M+1]; for(int j=0; j<=M; j++) { //求价值,下面这处错误 //dp[0][j] = (j>=objlist[0].weight)?(objlist[0].weight):(0); dp[j] = (j>=(objlist[0].weight))?(objlist[0].value):(0); //printf("dp[0][%d] = %d\n",j, dp[0][j]); } //对下面每一行[1, N-1],求动态规划式子 int alt_full = 0; int alt_notfull = 0; for(int i=1; i<N; i++) { for(int j=M; j>=0; j--) { alt_full = dp[j]; int temp_weight = objlist[i].weight; if(j >= temp_weight) { //alt_notfull = dp[i-1][j-temp_weight]+temp_weight; alt_notfull = dp[j-temp_weight]+objlist[i].value; } else { alt_notfull = 0; } dp[j] = MAX(alt_full, alt_notfull); //printf("dp[%d][%d] = %d\n",i,j, dp[i][j]); } } return dp[M]; }
n=int(input()) m=int(input()) w=[int(i) for i in input().split()] v=[int(i) for i in input().split()] res=[[-1 for j in range(m+1)] for i in range(n+1)] for i in range(n+1): res[i][0]=0 for j in range(m+1): res[0][j]=0 reslut=0 if n==0: result=0 else: for i in range(1,n+1,1): for j in range(1,m+1,1): if j<w[i-1]: res[i][j]=res[i-1][j] else: res[i][j]=max(res[i-1][j],res[i-1][j-w[i-1]]+v[i-1]) result=res[i][j] print(result)
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int main(){ int i, j, N, M, weight[101] = {0}, value[101] = {0}, f[101] = {0}; scanf("%d", &N); //物品件数 scanf("%d", &M); //背包承重 for(i=1;i<=N;i++){ scanf("%d", &weight[i]); } for(i=1;i<=N;i++){ scanf("%d", &value[i]); } //输入数据 for(i=1;i<=N;i++){ for(j=M;j>=weight[i];j--){ //从后向前 f[j] = max(f[j], f[j-weight[i]]+value[i]); } } printf("%d", f[M]); return 0; }
import java.util.*; import java.lang.Math.*; public class Main{ public static void main(String args[]) { Scanner in = new Scanner(System.in); int N = in.nextInt(); int M = in.nextInt(); int[] w = new int[N]; int[] v = new int[N]; int[][] dp = new int[N+1][M+1]; for(int i = 0; i < N; i++) { w[i] = in.nextInt(); } for(int i = 0; i < N; i++) { v[i] = in.nextInt(); } // 状态转移: dp[i][j] 前i个物品背包容量j物品最大价值 // 如果 w[i] > j dp[i][j] = dp[i-1][j]; 不拿 // 如果 w[i] <= j dp[i][j] = max(dp[i-1][j], dp[i][j-w[i]]+v[i]) for(int i = 1; i <= N; i++) { for(int j = 1; j <= M; j++) { if(j - w[i-1] < 0) { dp[i][j] = dp[i-1][j]; } else { dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-w[i-1]] + v[i-1]); } } } System.out.println(dp[N][M]); } }
#include<bits/stdc++.h> using namespace std; int main() { int N,M; while(cin>>N>>M) { vector<int> v(N); vector<int> w(N); int num; for(int i=0;i<N;i++) { cin>>num; w[i]=num; } for(int i=0;i<N;i++) { cin>>num; v[i]=num; } int dp[N+1][M+1]; memset(dp,0,sizeof dp); for(int i=1;i<=N;i++) { for(int j=w[i-1];j<=M;j++) { dp[i][j]=dp[i-1][j]; dp[i][j]=max(dp[i][j],dp[i-1][j-w[i-1]]+v[i-1]); } } cout<<dp[N][M]<<endl; } return 0; }
n = int(input()) w = int(input()) weights = list(map(int,input().split())) value = list(map(int,input().split())) dp = [0]*(w+1) #面对第i个物品,背包容量为j时的价值最大值 for i in range(1,n+1): for j in range(w,weights[i-1]-1,-1): dp[j] = max(dp[j-weights[i-1]]+value[i-1],dp[j]) print(dp[-1])
//标准01背包 import java.util.Scanner; public class Main{ public static void main(String[] args){ //开启对数据进行接收处理 Scanner scanner = newScanner(System.in); //物品的数量 intN = scanner.nextInt(); //背包的容量 intW = scanner.nextInt(); //建立物品的体积数组 int[] weight = newint[N + 1]; //建立物品的价值数组 int[] value = newint[N + 1]; //开始接收数据 //表示第i组数据的重量和价值 for(inti = 1;i <= N;i++){ weight[i] = scanner.nextInt(); } for(inti = 1;i <= N;i++){ value[i] = scanner.nextInt(); } scanner.close(); //开始干活 int[] dp = newint[W + 1]; dp[0] = 0; for(inti = 1;i <= N;i++){ for(intj = W;j >= weight[i];j--){ dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]); } } System.out.println(dp[W]); } }
#include<iostream> #include<vector> #include<algorithm> using namespace std; int knapsack(int N, int M, vector<int>& w, vector<int>& v){ int dp[M+1]; for(int i=0;i<=M;i++) dp[i] = 0; for(int i=1;i<=N;i++){ for(int j=M;j>=w[i];j--){ dp[j] = max(dp[j],dp[j-w[i]]+v[i]); } } int ans=0; for(auto p:dp){ if(p>ans){ ans = p; } } return ans; } int main(){ int N,M;//N件物品 M的容量 cin>>N>>M; vector<int> w(N+1);//质量 vector<int> v(N+1);//价值 for(int i=1;i<=N;i++) cin>>w[i]; for(int i=1;i<=N;i++) cin>>v[i]; int ans = knapsack(N,M,w,v); cout<<ans; return 0; }
n = int(input()) w = int(input()) w_list = [int(x) for x in input().split()] v_list = [int(x) for x in input().split()] def solution(): # dp[i][j]: 前i个物品且当前背包的容量为j时的最大价值 dp = [[0]*(w+1) for _ in range(n+1)] for i in range(1, n+1): for j in range(1, w+1): dp[i][j] = dp[i-1][j] if j >= w_list[i-1]: # max(不选物品i, 选物品i) dp[i][j] = max(dp[i-1][j], dp[i-1][j-w_list[i-1]]+v_list[i-1]) return dp[n][w] print(solution())