暴力搜索---新技能get

16 篇文章 0 订阅

   最近新学习了一种新的求解的方法,就是暴力搜索,在通常做题没有很明确的思路的时候,通常都会采用的一种方式。

我们知道,一个问题的解空间通常对应的是一棵树的方式进行组织的,那么我们可以通过根据题目中的条件描述来扫描

树中的每一个结点,对应的就是将问题的所有可能的解进行扫描一遍,从中选出满足要求的即为问题的答案了。

  这也就是人们常说的搜索,搜索的对象是解空间树。 当然,根据不同的情况而言,树中的结点个数可能会有很多,

很多情况下,在规定的时间之内是不能够搜索到全部的解所对应的顶点的,所以这也就随之产生了很多中搜索的方法:


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 的全部全排列


  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值