这是一道poj1184的题目,由于求解的是最优解,所以首先想到的就是使用广度优先搜索。对于这道题目我同时使用set容器,来作为状态判重。
代码如下:
在这里值得注意的地方如下:
1、由于重复状态的条件必须满足有相同的code和光标位置,所以在str结构体中重载operator<操作时,需要同时考虑code和pos两个域,保证这两个状态的都相同时,是不会被插入到set中的。因为对于set来说,他判断是否insert时发生冲突是通过两次使用operator<对两个状态进行检测,发现得出相同的结果。如果比较对象域是string这样的标准类型的话,那么在operator<函数中不能出现等于号,即写成这样是错误的:return a.code <= b.code,因为这样的话,就不会发生冲突了。
2、由于没有进行其他方面的优化,所以这个程序的效率是比较差的。
下面是我改用hash处理状态判重的一个程序:
这里我把光标的位置直接放到code的最后一位,这样直接作为字符串来处理,方便很多。但是测试下来,性能没有太大的提高,因为需要搜索的状态实在太多,到后面hash冲突现象很严重。
后来我用A*算法来优化BFS搜索,代码如下:
这里有一些值得注意的地方:
1、这里关闭列表使用的是set容器,另外和传统的A*算法不同,我这里没有将产生的已有状态,但还没有进入关闭列表的状态,加入到堆数据结构中,因为可以分析出来,在这道题目中,这些状态是不可能产生更好的搜索路径的。这样大大提高了搜索效率。
但是在有些例子下,还是搜索时间太长了,需要进一步剪枝优化。
在这些程序中使用到的一些技巧吧:
1、使用pair这个utility。声明定义pair,如:typedef pair<set<string>::iterator , bool > Pair ;
pair的两个域可以分别用first和second来引用。
2、set容器中的insert有一个版本为 pair insert( const TYPE &val ); 注意返回的是pair。
3、string中的一个append版本为:basic_string &append( size_type num, char ch ); 在字符串的末尾添加num个字符ch 。