最近新學習了一種新的求解的方法,就是暴力搜索,在通常做題沒有很明確的思路的時候,通常都會採用的一種方式。
我們知道,一個問題的解空間通常對應的是一棵樹的方式進行組織的,那麼我們可以通過根據題目中的條件描述來掃描
樹中的每一個結點,對應的就是將問題的所有可能的解進行掃描一遍,從中選出滿足要求的即爲問題的答案了。
這也就是人們常說的搜索,搜索的對象是解空間樹。 當然,根據不同的情況而言,樹中的結點個數可能會有很多,
很多情況下,在規定的時間之內是不能夠搜索到全部的解所對應的頂點的,所以這也就隨之產生了很多中搜索的方法:
1.暴力搜索法: 暴力搜索就是以枚舉的方法一一例舉解空間樹上的每一個結點,直至找到滿足要求的節點
主要有兩種類型題: 1. N個位置上的數據選取x 個,x 爲任意數字,對應的N 個數據每個數據,兩種狀態 0 , 1 ,0代表沒有被選取, 1 代表的是選取
這樣的話, N 個數據,對應的可能有 2^N 中可能性,當然解空間樹全部遍歷,對應 2^N 個頂點,當然對應的時間複雜度爲 O(2^n)
2. N個位置上的數據全部選取,但是選取的順序不同造成的結果不同------>對應的是對 N 進行全排列的方式,
這種實現方式有兩種,一種是暴力搜索對應的時間複雜度爲 O(N^N). 另一種是 O(N!) ,基於的是 dfs 搜索的方式。
2.二分搜索法 :通過每次將所訪問的解空間樹中的結點個數減半,即如果當前正在訪問的是解空間樹中的 i 頂點,
根據題目中所描述的信息,選取 i 頂點的左子樹或是右子樹,然後丟棄沒有選擇的子樹。對選取的子樹進行同樣的操作。
不過這種搜索方法要求的是,所搜索的關鍵字是需要有序排列的,這樣每次在進行二分的時候,
才能夠保證所訪問的樹的頂點 i 的左右子樹的數量都是相同的,並且(左子樹結點值)< i < (右子樹結點值) ,或是另一種序列。
3. DFS 搜索: 沿着一個起始訪問點,一直走直到訪問到底爲止,深度優先搜索。
通常實現起來可以通過遞歸的方式來對其進行實現。 也可以使用模擬棧的方式來實現。
4. BFS搜索: 逐層遍歷搜索樹中的每一個結點,BFS通常是用來選取最優解的方式,因爲逐層遍歷的方式,如果發現滿足題意的解的話,
該解必定位於的是所有的可能解中的距離根節點最近的一個結點,所以是最優解。
通常實現的方式是基於 隊列 作爲輔助數據結構來實現。
-------------------------------------------------------------------------------------------------------------------------------------------------------
1.暴力搜索法編程小練習:
1.1 已知,一個揹包能夠存放最大物體的重量爲 C , 現在有 N 個物體,對應的重量是 w[ 0 ... N-1], 請你求出,將物體中選取出一些 (x 個, x <= n ),
使得這 x 個物體的總共重量不超過揹包能夠承受的最大的重量C, 求出這個最大的重量。
輸入數據格式
N C
w[0] ....w[N-1]
輸出數據的格式
放入包中的物品最大重量值
</pre><pre name="code" class="cpp">#include <cstdio>
#include <string.h>
#include <algorithm>
int ans = 0 ;
int N , C , w[1005] ;
void input( )
{
memset( w , 0 , sizeof ( w ) ) ;
scanf("%d%d", &N , &C ) ;
for ( int i = 0 ; i < N ; i++ )
{
scanf("%d", &w[i]) ;
}
}
void dfs ( int step , int nowW )
{
if ( step == N )
{
if ( nowW <= C )
{
ans = ans>nowW?ans:nowW ;
}
return ;
}
dfs( step+1 , nowW) ;
dfs( step+1 , nowW+w[step] ) ;
}
int main ( void )
{
input() ;
dfs( 0 , 0 ) ;
if ( ans > 0 )
printf("ans = %d\n", ans ) ;
else
printf("No") ;
return 0 ;
}
1.2 已知,一個揹包能夠存放最重的重量爲 C , 現在有 N 個物體,N 個物體所對應的重量爲 w[ 0.. N-1] , 請你求出,在不對每個物品進行分割
並且不超過揹包限定總重量的情況下,能夠存放的最多物品的個數是多少,此時揹包的重量是多少,存放物品的編號是多少( 0...N-1)
輸入數據格式
N C
w[0] w[1] ... w[ N-1 ]
輸出數據的格式
最多的物品個數
揹包重量
所存放的物品編重量 ( 0 .. N-1 )
#include <cstdio>
#include <algorithm>
using namespace std ;
int N , C ;
int w[1001] ;
void input( )
{
scanf("%d%d", &N , &C) ;
for ( int i = 0 ; i < N ; i++ )
{
scanf("%d", &w[i]) ;
}
}
int cnt = 0 ;
int sum = 0 ;
void fun()
{
sort ( w , w+N ) ;
for ( int i = 0 ; i < N ; i++ )
{
if ( sum + w[i] <= C )
{
sum += w[i] ;
cnt++;
}
else
break;
}
}
int main ( void )
{
input() ;
fun() ;
if ( cnt != 0 )
{
printf("%d\n", cnt ) ;
printf("%d\n", sum) ;
for ( int i = 0 ; i < cnt ; i++ )
printf("%d ", w[i]) ;
}
else
printf("No") ;
return 0 ;
}
1.3 一直一個數組 a[ 0..n-1] 中有 n 個數值,現在給你一個固定的數值 K, 試問,在數組 a 中是否存在一組數值使得這些數值的和剛好等於 K
如果存在的話,輸出 Yes。 如果不存在的話,則輸出 No
輸入格式
n K
a[0] a[1] ... a[n-1]
輸出格式
Yes
No
#include <cstdio>
#include <string.h>
#include <iostream>
using namespace std ;
int a[101] ,n , k ;
bool ok = false ;
void input ()
{
scanf("%d%d", &n , &k ) ;
for ( int i = 0 ; i < n ; i++ )
cin>>a[i] ;
}
void dfs ( int step , int v )
{
if ( step == n )
{
if ( v == k ) ok = true ;
return ;
}
dfs( step+1, v+a[step] ) ;
dfs(step+1 , v ) ;
}
int main ( void )
{
input() ;
dfs ( 0 , 0 ) ;
if ( ok )
{
printf("Yes") ;
}
else
printf("No") ;
return 0 ;
}
在這裏突然發現一個問題,dfs 應該在不對其進行剪枝操作的前提下是暴力搜索的一種特例。
//1.4 給定一個數值N, 打印出 N 到 1 的全部全排列