您的位置:首页 > 其它

A*算法解决八数码问题

2013-02-19 11:48 357 查看
昨天啃了一阵子,终于啃下了大名鼎鼎的A*(AStar)算法。

A*跟BFS(宽度优先搜索)非常相似,只是多了一个启发函数跟结点的实时判断。

而A*算法的重点也就是启发函数,而且这没有固定的模版或者套路,完全看个人的设计能力。

其他的并不难。

参考了 http://hi.baidu.com/catro/item/4782da1769edbd721109b5e9

http://blueve.me/archives/684

这两篇写得非常好的文章。

废话不说了,稚嫩的代码如下:

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

//A*八数码

// 状态结构存储
struct State
{
int s[3][3];
int index,pre;
int g;
//打印路径
void Display()
{
for(int i = 0; i < 3; ++i)
{
for(int j = 0; j < 3; ++j)
{
cout << s[i][j] << ' ';
}
cout << endl;
}
}
//优先级比较
friend bool operator< (State n1, State n2)
{
return n1.g > n2.g;
}
bool equal(State goal)
{
for(int i = 0; i < 3; ++i)
{
for(int j = 0; j < 3; ++j)
{
if(s[i][j] != goal.s[i][j]) return false;
}
}
return true;
}
int fineZero(int flag)
{
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
if(s[i][j]==0)
{
if(flag==0) return i;
else return j;
}
}
};

//vector<State> States; // 存储所有的状态
//初始状态和目标状态
State inital,goal;
//开闭表
priority_queue<State> openTable;
vector<State> closeTable;
int direct[4][2]={{0,1},{0,-1},{1,0},{-1,0}}; //方向 右 左 下 上
/**
* 启发函数
* --------------------
* f(s) = g(s) + h(s)
* 其中 g(s) 由 g 数组给出
* h(s) = 与目标状态不一致点的个数
*/
int f(State node)
{
int rslt = node.g;  // g(s)
for(int i = 0; i < 3; ++i)    // h(s)
for(int j = 0; j < 3; ++j)
{
if(node.s[i][j] != goal.s[i][j])
{
rslt++;
}
}
return rslt;
}

bool isMove(int goalX , int goalY)
{
if(goalX < 0 || goalX>=3) return false;
if(goalY < 0 || goalY>=3) return false;
return true;
}

bool isCloseTableContain(State node)
{
State tmp;
for(vector<State>::iterator ite = closeTable.begin() ; ite != closeTable.end() ;ite++)
{
tmp = (State)*ite;
if(tmp.equal(node))
return true;
}
return false;
}

State AStar(State start)
{
// 初始状态
start.g = 0;
start.pre = -1;
openTable.push(start);

while(!openTable.empty())
{
// 找到最优的一个状态
State preState = openTable.top(); // 获取状态索引
openTable.pop();

// 插入close表
preState.index = closeTable.size();
closeTable.push_back(preState);

// 已找到目标状态
if(preState.equal(goal))
{
return preState;
}
// 尝试向四个方向扩展该状态
for(int i(0); i < 4; ++i)
{
State cur = preState;
int zeroX = cur.fineZero(0);
int zeroY = cur.fineZero(1);
// 取得带扩展状态的空位位置
int goalX = direct[i][0]+zeroX;
int goalY = direct[i][1]+zeroY;
// 确保移动合法
if(isMove(goalX, goalY))
{
// 交换移动0
int num = cur.s[goalX][goalY];
cur.s[goalX][goalY] = 0;
cur.s[zeroX][zeroY] = num;

// 判重
if(!isCloseTableContain(cur))
{
// 将新状态置入状态序列
cur.g = f(cur);
cur.pre = preState.index;
// 插入open表
openTable.push(cur);
}
}
}
}
}

State inputData()//录入数据
{
State aNode;
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
cin>>aNode.s[i][j];
}
}
return aNode;
}

//递归回溯求解
void disPlayWay(int index)
{
if(index == -1) return ;
State node = closeTable[index];
disPlayWay(node.pre);
node.Display();
cout<<"->"<<endl;
}

int main()
{
inital = inputData();
goal = inputData();
State result = AStar(inital);
cout<<"找到解答,移动步骤如下:"<<endl;
disPlayWay(result.index);
return 0;
}
/*
2 8 3
1 6 4
7 0 5
1 2 3
8 0 4
7 6 5
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: