背包问题:
-
0-1背包问题:给定n种物品和一个容量为V的背包,每种物品都有自己的重量w[i]和价值v[i],在限定的总重量内,选择其中若干件物品装入背包,使得背包中的物品总价值最大。
-
多重背包问题:相比起第一种,每种物品都有独立的数量可供选择使用
-
完全背包问题:相比起第一种,每种物品都可以无限重复选择
第一种:
#include <stdio.h>
#define max(a, b) ((a) > (b) ? (a) : (b))
//搞出最大值的函数
int main() {
int n, V;
scanf("物品数量:%d 背包容量%d", &n, &V);
int w[n], v[n];
int i,j;
for (i = 0; i < n; i++) {
scanf("%d %d", &w[i], &v[i]);
}
int dp[n+1][V+1];
for (i = 0; i <= n; i++) {
for (j = 0; j <= V; j++) {
dp[i][j] = 0;
// 初始化动态规划数组
}
}
for (i = 1; i <= n; i++) {
for (j = 1; j <= V; j++) {
if (w[i-1] <= j) {
// 当前物品重量小于等于背包容量,选择放入或不放入该物品,选择总价值更大的方案
dp[i][j] = max(dp[i-1][j-w[i-1]] + v[i-1], dp[i-1][j]);
} else {
// 当前物品重量大于背包容量,无法放入该物品,继承上一个状态的价值
dp[i][j] = dp[i-1][j];
}
}
}
printf("%d\n", dp[n][V]);
return 0;
}
随便提一嘴,博主的dev-c++版本似乎有些老,博主在最初几版代码老是报错,原因如下:
在 C99 标准之前,C 语言不允许在 for
循环中声明变量,而在 C99 标准及以后,C 语言支持在 for 循环中声明变量。博主就属于前者,
for (int i = 0; i < n; i++)
这种就会去报错,大家可以避免
第二种:
看起来和第一种差不多,实际上确实差不多,多了要用指针了,麻烦一些
使用了 malloc
函数来动态地分配了多个数组的内存空间,这些数组用于解决多重背包问题:
int *w = (int *)malloc(sizeof(int) * n);//存储每个物品的重量
int *v = (int *)malloc(sizeof(int) * n);//存储每个物品的价值
int *num = (int *)malloc(sizeof(int) * n); // 记录每种物品的数量
int *dp = (int *)malloc(sizeof(int) * (V + 1));
其中,w
数组存储每个物品的重量,v
数组存储每个物品的价值,num
数组记录每个物品的数量,dp
数组则用于存储求解过程中的结果,使用malloc原因是它可以动态分配内存,每次的数量价值重量都不一样,所以要动态的分配合理内存。
代码如下:
#include <stdio.h>
#include <stdlib.h>
//为了使用malloc函数
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
int main() {
int n, V;
printf("请输入物品数量和背包容量:");
scanf("%d %d", &n, &V);
// 输入每种物品的重量、价值和数量
int *w = (int *)malloc(sizeof(int) * n);
int *v = (int *)malloc(sizeof(int) * n);
int *num = (int *)malloc(sizeof(int) * n);
// 记录每种物品的数量
int i,j,k;
for (i = 0; i < n; i++) {
scanf("%d %d %d", &w[i], &v[i], &num[i]);
}
int *dp = (int *)malloc(sizeof(int) * (V + 1));
for (i = 0; i <= V; i++) {
dp[i] = 0;
}
// 遍历每种物品
for (i = 0; i < n; i++) {
// 对于每种物品,从背包容量到该物品重量来逆序遍历
for (j = V; j >= w[i]; j--) {
// 计算当前物品的最大可选数量
int maxNum = min(num[i], j / w[i]);
// 遍历当前物品的可选数量,更新动态规划数组
for (k = 1; k <= maxNum; k++) {
dp[j] = max(dp[j], dp[j - k * w[i]] + k * v[i]);
}
}
}
// 输出最大总价值
printf("最大总价值为:%d\n", dp[V]);
// 释放内存
free(dp);
free(w);
free(v);
free(num);
return 0;
}
第三种:
跟第二种差不多,思路一样
#include <stdio.h>
#include <stdlib.h>
#define max(a, b) ((a) > (b) ? (a) : (b))
int main() {
int n, V,i,j;
printf("请输入物品数量和背包容量:");
scanf("%d %d", &n, &V);
// 输入每种物品的重量和价值
int *w = (int *)malloc(sizeof(int) * n);
int *v = (int *)malloc(sizeof(int) * n);
for (i = 0; i < n; i++) {
scanf("%d %d", &w[i], &v[i]);
}
int *dp = (int *)malloc(sizeof(int) * (V + 1));
for ( i = 0; i <= V; i++) {
dp[i] = 0;
}
// 遍历每种物品
for ( i = 0; i < n; i++) {
// 对于每种物品,从该物品重量开始遍历
for ( j = w[i]; j <= V; j++) {
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
}
}
// 输出最大总价值
printf("最大总价值为:%d\n", dp[V]);
// 释放内存
free(v);
free(w);
free(dp);
return 0;
}