现在的位置: 首页 > 综合 > 正文

[ 算法 ] 广度优先搜索算法!

2014年06月27日 ⁄ 综合 ⁄ 共 2760字 ⁄ 字号 评论关闭

华容道游戏是非常经典的BFS应用的题目。

下面是几个我参考过的链接:

使用java语言实现,充分体现OOAD和数据结构的应用,讲的非常详细,但是太过于复杂了:

http://www.cppblog.com/tx7do/archive/2006/09/18/12691.html

简单版本的介绍,非常有用,而且有完整的源代码:

http://blog.chinaunix.net/u/19651/showart_395172.html

虽然讲的详细,但是代码也成这副样子,值得同情:

http://www.fjptsz.com/xxjs/xjw/rj/110.htm

 

下面是我通过这道题的一些体会:

 

1、重复状态的判重方法

 

在很多与走步有关的题目中,一般会涉及到重复状态的检测,在搜索过程中需要忽略掉这些重复状态,这样才能避免不必要的搜索代价。

我使用通过对局面做hash的方法来检测是否存在重复状态,只有不重复的新状态才插入到hash表中。原来hash函数是通过对grid[5][4]这个局面进行移位运算来产生分布均匀的hash值,但是效果始终不理想。

int getHashValue(char grid[5][4]) {
	
	int mask13=0x0001fff;		//低位连续的13个1 
	int mask19=0x007ffff;		//低位连续的19个1 
	
	int result=0,tmp;
	for(int i=0;i<5;i=i+2){
	
		tmp=(grid[i][0]<<24) | (grid[i][1]<<16) | (grid[i][2]<<8) | (grid[i][3]);
		result += (((tmp & (mask13<<13))>>13) | ((tmp & mask19)<<19));
		result ^=(grid[i+1][0]<<24) | (grid[i+1][1]<<16) | (grid[i+1][2]<<8) | (grid[i+1][3]);
		
	}
    result= (result<=0)? -result: result;
    
	return result%HashTableSize;	//最后一定要对HashTable取余 
}

 

后来我发现可以将局面转化为字符串的形式,然后对字符串进行hash处理,这样得到的hash函数效果非常好,因为本身对string就有一个很好的hash函数

int getHashValue(char grid[5][4]) {
	
	char* grid_begin= &grid[0][0];
	char* grid_end= &grid[5][0];
	string str(grid_begin , grid_end) ;
	
	
	int result=0 ;
	for( int i=0 ; i<str.length() ; i++)
		result = 37* result + str[i];
		
	result = result % HashTableSize ;
	
	if( result <0 )
		result += HashTableSize ;
		
	return result ;
	
	
}

 

注意string类型hash函数的写法,如果在取余操作后,result的值小于0,那么还要加上HashTableSize的值

 

通过这个hash函数:

1、C++中如何将字符数组转化为字符串呢?

利用string类的构造函数

string类的主要几个构造函数为:

string();
  string( size_type length, char ch );
  string( const char *str );
  string( const char *str, size_type length );
  string( string &str, size_type index, size_type length );
  string( input_iterator start, input_iterator end );

 

下面我给出几个测试例子:

#include<iostream>
#include<string>
using namespace std;

int main(){
	
	
	char init_grid[5][4]={				
	'v','c','0','v',/
	'0','0','0','0',/
	'v','h','0','v',/
	'0','s','s','0',/
	's','b','b','s'
	};
	
	char* grid_begin=&init_grid[0][0];		//通过首末指针来调用构造函数
	char* grid_end = &init_grid[5][0];
	string str(grid_begin,grid_end);
	cout<<str<<endl;
	
	char a[5]={
		'h','e','e','o','p'
	};
	
	//调用string的构造函数:string( const char *str ); 
	string str1(a,a+5);						//对于一维数组可以使用指针的思想
	cout<<str1<<endl;

	const char* b="hello";					//直接使用const char*参数调用构造函数
	string str2(b);
	cout<<str2<<endl;
	
	return 0;
	
}

 

可以看到这巧妙的使用第四个构造函数:string( input_iterator start, input_iterator end )

对于C++中的内置类型数据迭代器对应的其实就是指针,在这个例子中grid二维数组的末指针可以为 &grid[4][5],也可以是grid[5][0].

 

 这里如果直接使用string的第二构造函数  string( const char *str ); 并以 &grid[0][0]作为参数,获得的string对象中是有乱码的。

 

2、保证hash表的大小为素数

当hash表的大小为素数时,可以减少冲突的发生可能性。下面是一个获取某个数的下一个素数的测试程序:

#include<iostream>
#include<cstdio>
#include<fstream>
using namespace std;

bool isPrime(unsigned int a){
	
	if( a==2 || a == 3)
		return true ;
		
	if( a==1 || a%2 == 0 )
		return false ;
		
	for(int i=3 ; i*i<=a ; i+=2){
		
		if( a % i == 0)
			return false ;		
	}
	
	return true ;
}

int nextPrime(unsigned int a){
	
	if( a % 2 == 0)
		a++;
		
	for( ; !isPrime(a) ; a+=2) ;
	
	return a ;
}

int main(int argc,char* argv[]) {
	
	
	cout<<nextPrime(1<<18)<<endl;
	
	return 0;

}

转载文章出处:http://blog.csdn.net/urecvbnkuhbh_54245df/article/details/5850715

抱歉!评论已关闭.