首页 > 代码库 > 八数码问题——双向广度优先搜索解决

八数码问题——双向广度优先搜索解决

八数码问题:在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所看到的,要求对空格运行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态。

                                         技术分享

                                    技术分享

                                    技术分享

搜索顺序有两种:

(1)两个方向交替进行扩展

(2)每次选择节点少的那个扩展

一般来说方法(2)能够克服两端生长不平衡的现象

// eight.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;

#define N 3
#define SIZE 9
typedef unsigned char BYTE;
/*const int src[N][N] = { { 2, 5, 4 },
{ 3, 0, 7 },
{ 1, 8, 6 } };*/
const int src[N][N] = { { 8, 7, 1 },
{ 5, 2, 6 },
{ 3, 4, 0 } };

/*const int dst[N][N] = { { 1, 2, 3 },
{ 8, 0, 4 },
{ 7, 6, 5 } };*/
const int dst[N][N] = { { 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 0 } };

struct Code
{
	BYTE value[SIZE];
	bool operator== (const Code &a) const
	{
		for (int i = 0; i < SIZE;i++)
		if( a.value[i] !=value[i])
			return false;
		return true;
	}
	Code& operator=(const Code& a)
	{
		for (int i = 0; i < SIZE; i++)
		value[i] = a.value[i];
		return *this;
	}
};

Code up(Code a)
{
	int ii=-1;
	for (int i = 0; i < SIZE; i++)
		if (a.value[i] == 0)
		{
		ii = i;
		break;
		}
	if (ii > 2)
	{
		BYTE temp = a.value[ii - 3];
		a.value[ii - 3] = 0;
		a.value[ii] = temp;
	}
	return a;
}

Code right(Code a)
{
	int ii = -1;
	for (int i = 0; i < SIZE; i++)
		if (a.value[i] == 0)
		{
		ii = i;
		break;
		}
	if (ii>=0&&(ii+1)%3!=0)
	{
		BYTE temp = a.value[ii +1];
		a.value[ii +1] = 0;
		a.value[ii] = temp;
	}
	return a;
}
Code down(Code a)
{
	int ii = -1;
	for (int i = 0; i < SIZE; i++)
		if (a.value[i] == 0)
		{
		ii = i;
		break;
		}
	if (ii>=0&&ii <6)
	{
		BYTE temp = a.value[ii + 3];
		a.value[ii + 3] = 0;
		a.value[ii] = temp;
	}
	return a;
}


Code left(Code a)
{
	int ii = -1;
	for (int i = 0; i < SIZE; i++)
		if (a.value[i] == 0)
		{
		ii = i;
		break;
		}
	if (ii >= 0&&ii%3!=0)
	{
		BYTE temp = a.value[ii - 1];
		a.value[ii - 1] = 0;
		a.value[ii] = temp;
	}
	return a;
}

vector<Code>solution;

bool expand(vector<vector<Code>>&tobeexpanded, vector<vector<Code>>&a_b, vector<Code>&front_tobeexpanded, vector<Code>&front_a_b)
{
	vector<vector<Code>>bbb;
	vector<Code>::iterator it;
	front_tobeexpanded.clear();
	for (int i = 0; i < tobeexpanded.size(); i++)
	{
		if (!(up(tobeexpanded[i].back()) == tobeexpanded[i].back()) && find(tobeexpanded[i].begin(), tobeexpanded[i].end(), up(tobeexpanded[i].back())) == tobeexpanded[i].end())
		{
			it = find(front_a_b.begin(), front_a_b.end(), up(tobeexpanded[i].back()));
			if (it != front_a_b.end())
			{
				solution = a_b[it - front_a_b.begin()];
				reverse(tobeexpanded[i].begin(), tobeexpanded[i].end());
				solution.insert(solution.end(), tobeexpanded[i].begin(), tobeexpanded[i].end());
				return true;
			}
			front_tobeexpanded.push_back(up(tobeexpanded[i].back()));
			bbb.push_back(tobeexpanded[i]);
			bbb.back().push_back(up(tobeexpanded[i].back()));
		}
		if (!(right(tobeexpanded[i].back()) == tobeexpanded[i].back()) && find(tobeexpanded[i].begin(), tobeexpanded[i].end(), right(tobeexpanded[i].back())) == tobeexpanded[i].end())
		{
			it = find(front_a_b.begin(), front_a_b.end(), right(tobeexpanded[i].back()));
			if (it != front_a_b.end())
			{
				solution = a_b[it - front_a_b.begin()];
				reverse(tobeexpanded[i].begin(), tobeexpanded[i].end());
				solution.insert(solution.end(), tobeexpanded[i].begin(), tobeexpanded[i].end());
				return true;
			}
			front_tobeexpanded.push_back(right(tobeexpanded[i].back()));
			bbb.push_back(tobeexpanded[i]);
			bbb.back().push_back(right(tobeexpanded[i].back()));
		}
		if (!(down(tobeexpanded[i].back()) == tobeexpanded[i].back()) && find(tobeexpanded[i].begin(), tobeexpanded[i].end(), down(tobeexpanded[i].back())) == tobeexpanded[i].end())
		{
			it = find(front_a_b.begin(), front_a_b.end(), down(tobeexpanded[i].back()));
			if (it != front_a_b.end())
			{
				solution = a_b[it - front_a_b.begin()];
				reverse(tobeexpanded[i].begin(), tobeexpanded[i].end());
				solution.insert(solution.end(), tobeexpanded[i].begin(), tobeexpanded[i].end());
				return true;
			}
			front_tobeexpanded.push_back(down(tobeexpanded[i].back()));
			bbb.push_back(tobeexpanded[i]);
			bbb.back().push_back(down(tobeexpanded[i].back()));
		}
		if (!(left(tobeexpanded[i].back()) == tobeexpanded[i].back()) && find(tobeexpanded[i].begin(), tobeexpanded[i].end(), left(tobeexpanded[i].back())) == tobeexpanded[i].end())
		{
			it = find(front_a_b.begin(), front_a_b.end(), left(tobeexpanded[i].back()));
			if (it != front_a_b.end())
			{
				solution = a_b[it - front_a_b.begin()];
				reverse(tobeexpanded[i].begin(), tobeexpanded[i].end());
				solution.insert(solution.end(), tobeexpanded[i].begin(), tobeexpanded[i].end());
				return true;
			}
			front_tobeexpanded.push_back(left(tobeexpanded[i].back()));
			bbb.push_back(tobeexpanded[i]);
			bbb.back().push_back(left(tobeexpanded[i].back()));
		}
	}
	tobeexpanded = bbb;
	return false;
}
void DBFS()
{
	vector<vector<Code>>aa,bb;
	Code start, ending;
	for (int i = 0; i < SIZE; i++)
	{
		start.value[i] = src[i / 3][i % 3];
		ending.value[i] = dst[i / 3][i % 3];
	}
	vector<Code>a1, b1;
	a1.push_back(start);
	b1.push_back(ending);
	aa.push_back(a1);
	bb.push_back(b1);
	vector<Code>front_a, front_b;
	front_a.push_back(start);
	front_b.push_back(ending);
	while (true)
	{
		if (aa.size()>bb.size())
		{
			if(expand(bb, aa, front_b, front_a))
				return;
		}
		else
		{
			if(expand(aa, bb, front_a, front_b))
				return;
		}
	}
}



int _tmain(int argc, _TCHAR* argv[])
{

	DBFS();

	system("pause");
	return 0;
}



题目来源:NOIP2002提高组试题
描写叙述 Description
已知有两个字串 A$, B$ 及一组字串变换的规则(至多6个规则):
A1$ -> B1$
A2$ -> B2$
规则的含义为:在 A$中的子串 A1$ 能够变换为 B1$、A2$ 能够变换为 B2$ …。
比如:A$=‘abcd‘ B$=‘xyz‘
变换规则为:
‘abc’->‘xu’ ‘ud’->‘y’ ‘y’->‘yz’
则此时。A$ 能够经过一系列的变换变为 B$,其变换的过程为:
‘abcd’->‘xud’->‘xy’->‘xyz’
共进行了三次变换,使得 A$ 变换为B$。
输入格式 Input Format
A$ B$
A1$ B1$ \
A2$ B2$ |-> 变换规则
... ... /
全部字符串长度的上限为 20。


输出格式 Output Format
若在 10 步(包括 10步)以内能将 A$ 变换为 B$ 。则输出最少的变换步数;
否则输出"NO ANSWER!"
例子输入:
abcd xyz
abc xu
ud y
y yz
例子输出:
3
题目类型:双向广搜




八数码问题——双向广度优先搜索解决