【例题·搜索】八数码问题(A*)

I AK IOI !!! HZK,HXC,CZ IS SB !!!
我最强!!! 我把tourist 吊打!!!
你们都是菜鸡!!!

题目描述

在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

题解

这道题可以用 A ∗ A* A算法解决。

每一个状态由空格朝四个方向进行扩展,使用优先队列 B F S BFS BFS进行扩展。

在存储状态上可以看做九进制数存储在 m a p map map里。

然后就是估价函数的问题:

我们发现每一次移动空格的时候,只有一个格子发生改变,离目标状态的具体也只改变了一次,因此我们可以将当前状态和目标状态对应点直接的曼哈顿距离之和作为估价函数。即: f ( n o w ) = ∑ i = 1 9 ∣ s t x i − e d x i ∣ + ∣ s t y i − e d y i ∣ f(now)=\sum_{i=1}^{9} |stx_i-edx_i|+|sty_i-edy_i| f(now)=i=19stxiedxi+styiedyi

代码

#include 

using namespace std;

int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
map <int,int> dis;
map <int,bool> vis;
struct node
{
	int Map[3][3];
	int val ()
	{
		int sum=0;
		for (int i=0;i<3;++i)
		    for (int j=0;j<3;++j)
		        sum=sum*9+Map[i][j];
		return sum;
	}
	int func()
	{
		int sum=0;
		int last[3][3]={{1,2,3},{8,0,4},{7,6,5}};
		pair<int,int> temp[8];
		for (int i=0;i<3;++i)
		    for (int j=0;j<3;++j)
		        temp[last[i][j]]=make_pair(i,j);
		for (int i=0;i<3;++i)
		    for (int j=0;j<3;++j)
		        sum+=abs(i-temp[Map[i][j]].first)+abs(j-temp[Map[i][j]].second);
		return sum;
	}
	friend bool operator < (node a,node b)
	{
		return dis[a.val()]+a.func()>dis[b.val()]+b.func();
	}
	pair < int,int > pos ()
	{
		for (int i=0;i<3;++i)
		    for (int j=0;j<3;++j)
		        if (!Map[i][j]) return make_pair(i,j);
	}
	bool check(void)
	{
		int last[3][3]={{1,2,3},{8,0,4},{7,6,5}};
		for (int i=0;i<3;++i)
		    for (int j=0;j<3;++j)
		        if (last[i][j]^Map[i][j]) return 0;
		return 1;
	}
};
node st;
priority_queue< node > q;

inline bool in(int x,int y)
{
	return x>=0 && x<3 && y>=0 && y<3;
}

int main(void)
{
	freopen("input.in","r",stdin);
	freopen("output.out","w",stdout);
	for (int i=0;i<3;++i)
	    for (int j=0;j<3;++j)
	    {
	    	char c;
	    	cin>>c;
	        st.Map[i][j]=c-48;
	    }
	q.push(st);
	while (q.size())
	{
		node top=q.top();
		q.pop();
		if (vis[top.val()]) continue;
		vis[top.val()]=1;
		int nowx=top.pos().first;
		int nowy=top.pos().second;
		if (top.check()) return cout<<dis[top.val()],0;
		for (int i=0;i<4;++i)
		{
			node temp=top;
			int nx=nowx+dx[i];
			int ny=nowy+dy[i];
			if (!in(nx,ny)) continue;
			swap(temp.Map[nowx][nowy],temp.Map[nx][ny]);
			if (!dis[temp.val()] || dis[top.val()]+1<dis[temp.val()])
			{
				dis[temp.val()]=dis[top.val()]+1;
				q.push(temp);
			}
		}
	}
}

你可能感兴趣的:(搜索,[算法进阶指南]习题题解)