01背包算法
来源:互联网 发布:c语言集合的交并运算 编辑:程序博客网 时间:2024/06/03 15:37
核心思想:
知道背包的容量C,知道物品数量N,和物品的价值V[N+1]重量W[N+1],创建一个二阶矩阵m[N+1][C+1],其中第一行第一列不用,因为他的下标保证和i个物品一致
第一步:那么先从最后一个物品看一个一个看
容量从1~C开始看
如果最后一个物品能放入背包,就把它放进去,不能装的时候m[N][i]都是0,能装的时候就是最后一个物品价值的值
第二步:开始查看倒数第二个物品
当不能装入倒数第二个物品的时候,就把倒数第一个物品的值都往上移动,比如说如果倒二太大,不能装,但是倒一能装,那么这两个物品装入背包的最大价值就是倒一
当倒二可以装的话,那么当前容量减去倒二的质量,然后看倒一那一行的价值加上倒二的价值和倒一的价值比谁大,取大的那一个,防止如果装了倒二不能装倒一而值反而小了的情况
第三步:循环使用第二步
最后最大的背包容量的值在m[1][C]
关于查找
直接从第一行查找,如果第一行到第二行最大值变了那就说明第一个物品在背包,依次查到最后一行。
最后一行再进行判断,如果它非0那么就说明它也在背包里面
代码如下
#include<iostream>#include<iomanip>using namespace std;#include<malloc.h>#include<string.h>#include<stdlib.h>int * GetArray(int n){ int *s = (int*)malloc(sizeof(int)*n); if (NULL == s) exit(1); memset(s, 0, sizeof(int)*n); return s;}//获取一个n个单位的数组void FreeArray(int *p){ free(p);}//内存释放,防止内存泄漏void Print_Array(int *p, int n){ for (int i = 0; i < n; ++i) { cout << p[i] << " "; } cout << endl;}//打印数组int ** Get2Array(int n, int m){ int **s = (int**)malloc(sizeof(int*)*n); for (int i = 0; i < n; ++i) { s[i] = (int*)malloc(sizeof(int)*m); memset(s[i], 0, sizeof(int)*m); } return s;}//获取一个n*m的二维数组,并将其中的每个元素都设置为0void Free2Array(int **p, int n){ for (int i = 0; i < n; ++i) { free(p[i]); } free(p);}//释放一个二维数组的空间void Print_2Array(int **p, int n, int m){ for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { cout << setw(3) << p[i][j]; } cout << endl; } cout << endl;}//打印二维数组//////////////////////////////////////int Knapsack(int *W, int *V, int n, int c, int **m){//n = 5 c = 10 w是重量 v是价值 c是容量 n是数目 //int W[N + 1] = { 0,2,2,6,5,4 } //int V[N + 1] = { 0,6,3,5,4,6 } int i, j; for (j = 1; j <= c; ++j)// { if (j >= W[n])//j = 1~10 m[n][j] = V[n]; else m[n][j] = 0;//m[5][1~10] }//仅仅针对最后一个物品,我有的容量的最大值是 Print_2Array(m, n + 1, c + 1); for (i = n - 1; i >= 1; --i)//从(下标)n-1行到第一行 { for (j = 1; j <= c; ++j)//开始有两个物品 { if (j < W[i])//j < 下标为i的重量 m[i][j] = m[i + 1][j];//容量小于i物品的重量,就把之前的值放上来 else {//拿之前的m的值和 减去当前物品重量的值加上当前物品价值的值比较 m[i][j] = m[i + 1][j] > m[i + 1][j - W[i]] + V[i] ? m[i + 1][j] : m[i + 1][j - W[i]] + V[i]; } } Print_2Array(m, n + 1, c + 1); } return m[1][c];//最后的m[1][c]就是他这个背包能够装载的最大值的值}void Traceback(int *W, int **m, int n, int c, int *X){ //n是物品数量 5 //c是背包容量 10 //m存放刚得出的二阶矩阵 //W是重量 int i; for (i = 1; i < n; ++i)//1 ~ 5 { if (m[i][c] != m[i + 1][c]) {//如果最后的最大值发生改变了,说明i物品被放进去了会改变最大,所以i物品进入了最后的背包 X[i] = 1; c -= W[i];//重量减去i物品的重量 } } if (i == n)//如果i==n那就遍历完了,但是还不知道最后一个有没有装进去 { if (m[i][c] != 0)//如果最后一个不等于0那么就说明他也被装入了背包 { X[i] = 1; } }}void main(){ const int N = 5;//五个物品 const int C = 10;//容量 int **m = Get2Array(N + 1, C + 1);//建立一个6*11的二维矩阵,第一列第一行不用 int W[N + 1] = { 0,2,2,6,5,4 };//五个物品的重量 int V[N + 1] = { 0,6,3,5,4,6 };//五个物品的价值 int X[N + 1] = { 0,0,0,0,0,0 }; int maxv = Knapsack(W, V, N, C, m); cout << maxv << endl; Print_2Array(m, N + 1, C + 1); Traceback(W, m, N, C, X); for (int i = 1; i <= N; ++i)//拿哪些物品 { if (X[i]) { cout << i << " "; } } cout << endl;}
拓展
小萌是个WOW发烧友,每天都痴迷于他的法师号。精诚所至金石为开,小萌穿越到WOW的世界中了…
初来乍到的小萌在暴风城的小巷中,遇见了一位善良的德鲁伊。德鲁伊听了小萌的故事,打算帮助他在WOW这个世界好好活下去,于是,把自己的东西都给了小萌了…
德鲁伊的东西太多了,于是小萌去拍卖行买了几个包裹,一切妥当之后,小萌开始把东西装进包裹里。
不过,因为小萌穿越时候脑袋先着地,所以脑子不好用,每次他拿起一个物品,要不装进包里,要不就直接扔掉…
而且,一个背包一旦不往里装东西,小萌就会封上口不再用…
现在,告诉你小萌每个物品的体积,背包的个数和容量,以及小萌拿物品的顺序,你要帮助小萌求出他能拿走多少东西。
#include <iostream>#include <string.h>#include <vector>#include <algorithm>using namespace std;int main(){ int N;//物品个数 int T;//背包容量 int M;//背包个数 int b[25][25][25]; cin >> N >> T >> M; int *arr = new int[N + 1]; arr[0] = 0; for (int i = 1; i < N + 1; ++i) { cin >> arr[i]; } memset(b, 0, sizeof(b)); for (int i = 1; i <= M; ++i)//背包个数 { for (int j = 1; j <= N; ++j)//物品个数 { for (int k = 1; k <= T; ++k) { if (k >= arr[j]) { b[i][j][k] = max(max(b[i][j - 1][k], b[i][j - 1][k - arr[j]] + 1), b[i - 1][j][T]); } else { b[i][j][k] = max(b[i][j - 1][k], b[i - 1][j][T]); } } } } cout << b[M][N][T] << endl; return 0;}
给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)
例如:给定一个长度为8的数组A{1,3,5,2,4,6,7,8},则其最长的单调递增子序列为{1,2,4,6,7,8},长度为6.
#include <iostream>using namespace std;int getMax(int *arr, int len){ int b[100] = { 0 };//可以动态但是关键是算法思路所以我就不纠结细节了 b[0] = 1; int result = 1; for (int i = 1; i < len; ++i) { int max = 1; for (int j = i - 1; j >= 0; --j) { int tmp = 0; if (arr[i] > arr[j]) { tmp = b[j] + 1; } if (tmp > max) { max = tmp; } } b[i] = max; if (max > result) { result = max; } } return result;}int main(){ int arr[8] = { 1,3,5,2,4,6,7,8 }; cout << getMax(arr, 8) << endl; return 0;}
- 算法杂谈--01背包
- [算法]01背包问题
- 01背包-近似算法
- 01背包算法
- 算法提高 01背包
- 算法提高 01背包
- 算法提高 01背包
- 算法提高 01背包
- 算法提高 01背包
- 算法提高 01背包
- 【算法】01背包问题
- 算法-01背包1
- 算法-01背包2
- 01背包-回溯算法
- [面试算法] 01背包 && 完全背包
- 动态规划背包算法(01背包和完全背包)
- 01背包问题 原理 算法
- 01背包源码核心算法
- 前端开阔视野
- $_SERVER函数获取的内容解释
- 商品亲和性分析示例 - Python 数据挖掘
- 互联网网站架构升级----消息中间件的实现方案
- node.js新手入门
- 01背包算法
- IE和移动端兼容性
- 使用Dom4j解析XML
- git手册
- Java开发第一天(jdk)
- 关于MongoDB你需要知道的几件事
- Java开发第二天
- Java开发第三天(安装mysql)
- rsync配置