动态规划是以空间换时间,通过使用大量空间存储已经计算的数据,从而使后面的数据运算更加简便,因此在使用大量空间的弊端下,定义动态数组可以使空间不被浪费,所以在动态规划经典题目——01背包问题中,作者动态定义结构体数组,二维数组。
题目
图片来自网上
一、动态生成结构体数组
与动态生成整型类似,结构体数组只不过将整型所需空间换成结构体所需要的空间(sizeof的不同),例:
struct object {
int volume;
int value;
};
object *obj;
// ob_num为输入值
obj = (object *)calloc(ob_num + 1, sizeof(object));
calloc 与 malloc的不同在于 calloc 在开辟内存空间时已经将元素赋值为零,同时calloc格式与malloc略有不同(calloc括号中需要将数量与类型空间大小以逗号隔开,而malloc以*号相连)。
该结构体包含两个整型,volume表示体积,value表示价值,这样物体信息的结构体就定义好了。
二、动态定义二维数组
一维数组的动态生成需要一个指针,可以想到,只需定义一个指针数组,就可以动态定义二维数组了。首先得动态生成指针数组,就需要用到一个指向指针的指针类型int **table,通过这个第二层的指针,就可以生成一个指针数组,如下
table = (int **)calloc(ob_num + 1, sizeof(int *));
其中,ob_num+1表示开辟的数目,sizeof(int *)表示单个数目所需的空间大小。
接着与一维数组类似,加个for循环即可:
for (int i = 0; i < ob_num + 1; i++)
table[i] = (int *)calloc((bagV + 1), sizeof(int));
动态定义讲完了,接下就到了动态规划时间。
二、动态规划原理——01背包
动态规划就是通过记录原来的数据,为接下来进行的数据计算服务。我们一般以数组的下标作为存储的的地址,在01背包中我们定义了一个二维数组存放每个状态下的最优解;
二维数组的构成:
横轴下标代表背包容量 且从0开始,因为在计算容量为一时,需要调用容量为零的最优解--就是0;
纵轴下标代表物品编号 从零开始但第0行表示物品体积0价值0,方便后面第一行的动态规划。
关键:
以下面数据为例
4(物品个数) 8(背包容量)
物品体积 物品价值
2 3
3 4
4 5
5 6
以【3,6】为例,在此时判断 容量6减去编号为3的物体的体积4,然后在上一行找到对应的数据;
找到[2,6-4]=[2,2],这时的最优解是【2,2】的数据3,2+4=6(等于当列的体积),求出此时的总价值,3+5=8;大于上一行的最优解,存储下来。
ps:只能往上一行进行比较,因为与当行比较就会导致重复,所以应当与上一行对应位置比较。
代码如下:i表示背包容量,j表示编号;
for (int i = 0; i <= bagV; i++)
for (int j = 1; j <= ob_num; j++) {
if (obj[j].volume > i)
table[j][i] = table[j - 1][i];
else if (table[j - 1][i - obj[j].volume] + obj[j].value > table[j - 1][i])
table[j][i] = table[j - 1][i - obj[j].volume] + obj[j].value;
else
table[j][i] = table[j - 1][i];
}
通过求出每个背包容量的最优解,在最后一行最后一列就是能装的最大价值;
完整代码
#include <stdio.h>
#include <stdlib.h>
struct object {
int volume;
int value;
};
int max(int a, int b) {
return (a > b) ? a : b;
}
int main() {
int ob_num, bagV, ** table, res = 0, swap;
struct object *obj;
scanf("%d%d", &ob_num, &bagV);
obj = (object *)calloc(ob_num + 1, sizeof(object));
table = (int **)calloc(ob_num + 1, sizeof(int *));
for (int i = 0; i < ob_num + 1; i++)
table[i] = (int *)calloc((bagV + 1), sizeof(int));
for (int i = 1; i < ob_num + 1; i++)
scanf("%d%d", &obj[i].volume, &obj[i].value);
for (int i = 0; i < ob_num + 1 - 1; i++)
for (int j = 0; j < ob_num + 1 - i - 1; j++)
if (obj[j].volume > obj[j + 1].volume) {
swap = obj[j].volume;
obj[j].volume = obj[j + 1].volume;
obj[j + 1].volume = swap;
swap = obj[j].value;
obj[j].value = obj[j + 1].value;
obj[j + 1].value = swap;
}
for (int i = 0; i <= bagV; i++)
for (int j = 1; j <= ob_num; j++) {
if (obj[j].volume > i)
table[j][i] = table[j - 1][i];
else if (table[j - 1][i - obj[j].volume] + obj[j].value > table[j - 1][i])
table[j][i] = table[j - 1][i - obj[j].volume] + obj[j].value;
else
table[j][i] = table[j - 1][i];
}
for (int i = 0; i < ob_num + 1; i++) {
for (int j = 0; j < bagV + 1; j++)
printf("%d ", table[i][j]);
printf("\n");
}
for (int i = 0; i < ob_num; i++)
free(table[i]);
free(table);
return 0;
}