1. 程式人生 > >暴力搜尋演算法淺顯易懂

暴力搜尋演算法淺顯易懂

基礎演算法之 暴力搜尋

演算法說明

暴力演算法也叫蠻力演算法,之所以稱為暴力,是因為該演算法是列舉當前所有出現的情況, 從而得到需要的情況。該演算法可以求的一些情況較少的問題的解,若問題規模太大,該演算法便不適用。

演算法分析

若給定一個集合 α ,求得該集合的所有子集,求得的子集即為某種情況,列出所有子集及是暴力演算法。比如給定一個數組 [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();
}

總結

對於暴力搜尋,最重要的是對於當前元素的選擇或者不選擇,另外對於語言來說,遞迴會生成函式呼叫棧,儲存當前的資料,不用多考慮陣列的引用問題。