基础算法之 暴力搜索
算法说明
暴力算法也叫蛮力算法,之所以称为暴力,是因为该算法是枚举当前所有出现的情况,
从而得到需要的情况。该算法可以求的一些情况较少的问题的解,若问题规模太大,该算法便不适用。
算法分析
若给定一个集合 α ,求得该集合的所有子集,求得的子集即为某种情况,列出所有子集及是暴力算法。比如给定一个数组 [1, 3, 5] ,其所有子集为 [ ],[ 1 ],[ 3 ],[ 5 ],[ 1, 3 ],[ 1, 5 ], [ 3, 5 ], [ 1, 3, 5 ] 共八种情况。对于一个元素数量为 n 的集合来说,其子集数目为 2 的 n 次方。证明为: 对于集合中的每个元素,都有选择或者不选择两种情况,则 全部情况为 2 的 n 次方,该证明即为算法的核心。
问题示例
背包问题
给定一定数量的物品,每个物品都有其重量和价值,给定一个容量为 c 的背包,用该背包装物品,求 装的物品价值之和为最大的情况。
问题分析
设集合 A ,其元素为每个物品,利用暴力搜索算法列出集合 A 的所有子集,在其子集中找到物品价值之和最大的情况即可。对于该问题选择的数据结构,在此我用的是一个一维数组存放物品的重量,另一个一维数组存放物品的价值,对应下标即可。
代码示例(C语言)
#include<stdio.h>
int goods_all = 5; /* 物品数量 */
int goods_weight[5] = {1, 3, 6, 8, 12}; /* 物品的重量 */
int goods_value[5] = {1, 4, 8, 10, 20}; /* 物品的价值 */
int package = 20; /* 背包容量 */
int maxValue = 0; /* 当前最大价值(后面用到)*/
int choose[5]; /* 存放最优方案的物品下标 */
/* 输出结果函数
*/
void outputResult() {
for (int i = 0; i < goods_all && choose[i] != -1; i++)
{
printf("重量:%d,价值:%d\n", goods_weight[choose[i]], goods_value[choose[i]]);
}
}
/* 存放当前最优方案(不断的更新 choose 数组)
@param goods_list[] 当前的选择项数组
@param goods_num 当前的选择项 数目
*/
void storeChoose(int goods_list[], int goods_num){
for (int i = 0; i < goods_all; i++) choose[i] = -1;
for (int i = 0; i < goods_num; i++) choose[i] = goods_list[i];
}
/* 暴力枚举所有方案(递归实现)
@param goods_list 存放当前方案的数组
@param goods_num 当前选择的物品数目
@param goods_index 当前选择或不选择的物品下标
*/
void chooseGoods(int goods_list[],int goods_num, int goods_index){
/* 当物品的下标到最后一个物品时,即枚举完毕 ,
此时 遍历当前方案 goods_list[], 若当前方案价值
大于 当前的 maxValue ,则重写 choose数组
*/
if (goods_index == goods_all)
{
int value = 0, weight = 0;
for (int i = 0; i < goods_num; i++)
{
weight += goods_weight[goods_list[i]];
value += goods_value[goods_list[i]];
}
if (weight <= package && value > maxValue)
{
storeChoose(goods_list, goods_num);
maxValue = value;
}
}else
{
/* 不选择当前物品 */
chooseGoods(goods_list, goods_num, goods_index + 1);
/* 选择当前物品 */
goods_list[goods_num] = goods_index;
goods_num ++;
chooseGoods(goods_list, goods_num, goods_index + 1);
}
}
int main(){
int arr[5];
chooseGoods(arr, 0, 0);
outputResult();
}
总结
对于暴力搜索,最重要的是对于当前元素的选择或者不选择,在这里能保存数组的多样性是因为下标的原因,因为选择的元素都存在了数组一端。