双向广度搜索,从初始状态向下,从目标状态向上,进行双向搜索。广度优先可以保证得到的结果是最优的。搜索过程中要保存搜索路径(链表),以及搜索得到的状态(Map)。两个方向的搜索扩展节点时所作的操作不同,需要注意。如下是一个牛人写的双向搜索例题,很有代表性。
问题:一个3×3的方格里填入1-9九个数字,可以顺时针和逆时针旋转每一个2×2的方格,顺时针转或逆时针转90度算一次操作,问如何用最快的办法达到目标状态。 (类似于魔方)
比如说
1 2 3 4 1 3
4 5 6 -> 左上角顺时针旋转 -> 5 2 6
7 8 9 7 8 9
初始状态: 1 2 3
4 5 6
7 8 9
目标状态:4 1 2
7 5 6
8 9 3
//TurnCard.h
#include <iterator>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
#include <map>
using namespace std;
struct _node
{
string data;
struct _node* parent;
};
typedef struct _node Node;
typedef pair <string, Node*> Map_Pair;
int leftCorner[] = {0,1,4,3};
int rightCorner[] = {1,2,5,4};
int leftDownCorner[] = {3,4,7,6};
int rightDownCorner[] = {4,5,8,7};
int antiLeftCorner[] = {1,4,3,0};
int antiRightCorner[] = {2,5,4,1};
int antiLeftDownCorner[] = {4,7,6,3};
int antiRightDownCorner[] = {5,8,7,4};
class TurnCard
{
public:
TurnCard();
~TurnCard();
private:
Node* findInTheOpenList(string data);
Node* findInTheReverseOpenList(string data);
string expand(Node* data,int direction);
string reverseExpand(Node* data,int direction);
void pushToTheQueue(Node* node);
void pushToTheReverseQueue(Node* node);
string turnByClockWise(string data,int officer[]);
string turnByAntiClockWise(string data,int officer[]);
private:
string Run();
void PrintPath(Node* data);
void PrintReversePath(Node* data);
public:
void Go();
private:
string start;
string target;
map <string,Node*> OpenList;
queue<Node*> Candidates;
map <string,Node*> reverseOpenList;
queue<Node*> reverseCandidates;
};
// TurnCards.cpp : Try to find the path of the Turnable Pants using bidirectional BFS.
// Author: Fengdong
// Company:
// History: Created : 9,Apr. 2008
#include "stdafx.h"
#include "TurnCards.h"
TurnCard::TurnCard()
{
start = "123456789";
target = "412756893";
Node* startNode = new Node();
startNode->data = start;
startNode->parent = NULL;
OpenList.insert(Map_Pair(start,startNode));
pushToTheQueue(startNode);
Node* targetNode = new Node();
targetNode->data = target;
targetNode->parent = NULL;
reverseOpenList.insert(Map_Pair(target,targetNode));
pushToTheReverseQueue(targetNode);
}
TurnCard::~TurnCard()
{
map<string,Node*>::const_iterator itor ;
for( itor = OpenList.begin();itor!=OpenList.end();itor++)
{
delete itor->second;
}
for( itor = reverseOpenList.begin();itor!=reverseOpenList.end();itor++)
{
delete itor->second;
}
}
Node* TurnCard::findInTheOpenList(string data)
{
map<string,Node*>::const_iterator itor ;
itor = OpenList.find(data);
if (itor == OpenList.end())
return NULL;
else
return itor->second;
}
Node* TurnCard::findInTheReverseOpenList(string data)
{
map<string,Node*>::const_iterator itor ;
itor = reverseOpenList.find(data);
if (itor == reverseOpenList.end())
return NULL;
else
return itor->second;
}
void TurnCard::pushToTheQueue(Node* node)
{
Candidates.push(node);
}
void TurnCard::pushToTheReverseQueue(Node* node)
{
reverseCandidates.push(node);
}
string TurnCard::turnByClockWise(string data,int officer[])
{
string _data = data;
char tmp = _data[officer[3]];
for (int i=3;i>0;i--)
_data[officer[i]] = _data[officer[i-1]];
_data[officer[0]] = tmp;
return _data;
}
string TurnCard::turnByAntiClockWise(string data,int officer[])
{
string _data = data;
char tmp = _data[officer[0]];
for (int i=0;i<3;i++)
_data[officer[i]] = _data[officer[i+1]];
_data[officer[3]] = tmp;
return _data;
}
string TurnCard::expand(Node* node,int direction)
{
string _data ;
switch ( direction )
{
case 0:
_data = turnByClockWise(node->data,leftCorner);
break;
case 1:
_data = turnByClockWise(node->data,rightCorner);
break;
case 2:
_data = turnByClockWise(node->data,leftDownCorner);
break;
case 3:
_data = turnByClockWise(node->data,rightDownCorner);
break;
}
Node* _node = new Node();
_node->data = _data;
_node->parent = node;
if (!findInTheOpenList(_data))
{
OpenList.insert(Map_Pair(_data,_node));
pushToTheQueue(_node);
}
Node* target = findInTheReverseOpenList(_data);
if (target)
{
return _data;
}
else
{
return "";
}
}
string TurnCard::reverseExpand(Node* node,int direction)
{
string _data ;
switch ( direction )
{
case 0:
_data = turnByAntiClockWise(node->data,antiLeftCorner);
break;
case 1:
_data = turnByAntiClockWise(node->data,antiRightCorner);
break;
case 2:
_data = turnByAntiClockWise(node->data,antiLeftDownCorner);
break;
case 3:
_data = turnByAntiClockWise(node->data,antiRightDownCorner);
break;
}
Node* _node = new Node();
_node->data = _data;
_node->parent = node;
if (!findInTheReverseOpenList(_data))
{
reverseOpenList.insert(Map_Pair(_data,_node));
pushToTheReverseQueue(_node);
}
Node* target = findInTheOpenList(_data);
if (target)
{
return _data;
}
else
{
return "";
}
}
string TurnCard::Run()
{
Node* node;
Node* rnode;
string joint;
while(true)
{
node = Candidates.front();
Candidates.pop();
rnode = reverseCandidates.front();
reverseCandidates.pop();
for ( int i=0; i< 4;i++)
{
joint = expand(node,i);
if ( joint.length() != 0)
return joint;
}
for( int i=0;i<4;i++)
joint = reverseExpand(rnode,i);
if ( joint.length() != 0)
return joint;
}
}
void TurnCard::PrintPath(Node* node)
{
if ( node->parent != NULL)
PrintPath(node->parent);
for ( int i=0 ; i< 9; i++)
{
cout << " "<<node->data[i] <<" ";
if ( (i+1) % 3 == 0)
cout<< endl;
}
cout << endl;
}
void TurnCard::PrintReversePath(Node* node)
{
while(node)
{
for ( int i=0 ; i< 9; i++)
{
cout << " "<<node->data[i] <<" ";
if ( (i+1) % 3 == 0)
cout<< endl;
}
cout << endl;
node = node->parent;
}
}
void TurnCard::Go()
{
string interfacer = Run();
Node* node = findInTheOpenList(interfacer);
PrintPath(node->parent);
Node* rnode = findInTheReverseOpenList(interfacer);
PrintReversePath(rnode);
}
int _tmain(int argc, _TCHAR* argv[])
{
TurnCard* tc = new TurnCard();
tc->Go();
delete tc;
return 0;
}