华容道游戏是非常经典的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