A算法解九宫格

       以前写拼图游戏的时候就有个疑问:如果随机生成每个图片的位置的话,这个拼图可能是永远也解不出来的。但是当时不知道如何去解一个九宫格问题。

       最近了解了一下搜索算法,发现其实很多很多的问题都可以归结为对状态空间树的搜索,搜出来最优解。但是问题的解空间往往是巨大的,超出了计算机的计算能力。搜的所称中如何减少向下搜索的分支非常重要。而启发式搜索算法,着重于先搜那些可能快速达到终点状态的分支,来减少搜索时间。

      启发式算法的重点在于如何启发,这是个经验加艺术的技术。启发式算法的启发函数就像是hash表的hash函数一样,设计好了非常牛;空间效率,时间效率都别的算法无可比拟的,甚至说是计算机不可超越的。

      练练手,写了一个九宫格的程序。

      

     代码如下(启发函数太简单,复杂情况计算很慢):

     


//用A*算法解决9宫格问题
// 
 
#include<assert.h>
#include<iostream>
#include<algorithm>
#include<time.h>
#include<queue>
#include<string>
#include<vector>
using namespace std;

int rem[10][2]={{0,0},{0,0},{0,1},{0,2},{1,2},{2,2},{2,1},{2,0},{1,0},{1,1}};
struct Node
{
	char data[3][3];  //记录各个格子里的数字
	string key;       //当前节点的键值  用以唯一标示一个结点  为简便起见,我们用 data[0][0]+data[[0][1]
	                  //+data[0][2]+data[1][0]+...data[2][2]表示

	string theWay;    //记录父节点如何移动后产生了当前节点 用以输出结果时 向上查找路径 
	                  //'1'向左 '2'向右 '3' 向上 '4'向下 
	int dist;         //当前结点里目标结点的“距离”  “距离”越小,表示当前结点能通过少量的移动即可达到目标节点
	int dept;         //当前节点在搜索树种深度
	bool moveLeft(string &next)
	{
		int i,j;
		for(i=0;i<3;i++)
		{
			for(j=0;j<3;j++)
			{
				if(data[i][j]=='9')
					break;
			}
			if(j!=3)
				break;
		}
		if(j>0) //可以左移
		{
			next=key;
			swap(next[3*i+j],next[3*i+j-1]);
			return true;
		}
		return false;
	}
	bool moveRight(string &next)
	{
		int i,j;
		for(i=0;i<3;i++)
		{
			for(j=0;j<3;j++)
			{
				if(data[i][j]=='9')
					break;
			}
			if(j!=3)
				break;
		}
		if(j<2) //可以右移
		{
			next=key;
			swap(next[3*i+j],next[3*i+j+1]);
			return true;
		}
		return false;
	}
	bool moveDown(string &next)
	{
		int i,j;
		for(i=0;i<3;i++)
		{
			for(j=0;j<3;j++)
			{
				if(data[i][j]=='9')
					break;
			}
			if(j!=3)
				break;
		}
		if(i<2) //可以下移
		{
			next=key;
			swap(next[3*i+j],next[3*(i+1)+j]);
			return true;
		}
		return false;
	}
	bool moveUp(string &next)
	{
		int i,j;
		for(i=0;i<3;i++)
		{
			for(j=0;j<3;j++)
			{
				if(data[i][j]=='9')
					break;
			}
			if(j!=3)
				break;
		}
		if(i>0) //可以上移
		{
			next=key;
			swap(next[3*i+j],next[3*(i-1)+j]);
			return true;
		}
		return false;
	}
	bool isFinal()
	{
		if(key=="123894765")
			return true;
		return false;
	}
	friend bool operator < (const Node &node1,const Node &node2)
	{
		return node1.dist>node2.dist;
	}
	Node(string Key,int depth,string par)
	{
		
		theWay=par;
		dept=depth;
		key=Key;
		for(int i=0;i<9;i++)
		{
			data[i/3][i%3]=key[i];
		}
		//计算dist
		dist=dept;
		/*for(int i=1;i<9;i++)
		{ 
			if(data[rem[i][0]][rem[i][1]]!='9')
			{
				if(data[rem[i][0]][rem[i][1]]+1 != data[rem[i+1][0]][rem[i+1][1]])
					dist+=6;
			}
		}*/
		
		for(int i=0;i<3;i++)
		{
			for(int j=0;j<3;j++)
			{
			    
				 dist+= abs(i-rem[data[i][j]-'0'][0])+abs(j-rem[data[i][j]-'0'][1]) ;
			    
			}
		}   

	}
};
class NineBox
{
private:
	char *first_key;
	void input();
	
	void output(Node &final);
public:
	NineBox()
	{
		first_key=new char[10];
	}
	~NineBox()
	{
		delete []first_key;
	}
	void run();
};
void NineBox::output(Node &final)
{
	int len=final.theWay.length();
	for(int i=0;i<len;i++)
	{
		switch(final.theWay[i])
	    {
		case  '1':
			cout<<"向左->";
			break;
		case '2':
			cout<<"向右->";
			break;
		case  '3':
			cout<<"向上->" ;
			break;
		case '4':
			cout<<"向下->";
			break;
		}
	}
	cout<<"成功!"<<endl;
}
void NineBox::input( )
{
	cout<<"请输入九宫格的初始状态字符串:"<<endl;
	while(cin>>first_key)
	{
		char *temp=new char[10];
		memcpy(temp,first_key,10);
		sort(temp,temp+9);
		int i;
		for(i=0;i<9;i++)
		{
			if(temp[i]!=('1'+i))
				break;
		}
		if(i==9)
			break;
		else
		{
			cout<<"输入不合法,请重新输入:"<<endl;
		}
	}
	
}
void NineBox::run()
{
	priority_queue<Node> open;    //未访问过的结点表
	 
	vector<string> closed;          //访问过的结点表
	input(); 
	Node start(first_key,0,"");
	open.push(start);
	//放入closed表
	closed.push_back(start.key);
	while(!open.empty())
	{
		Node now=open.top();
		 
		open.pop();
	 
		if(now.isFinal()) //找到路径
		{
			output(now);
			return ;
		}
		string next="";
		if(now.moveLeft(next))
		{
			if(!( find(closed.begin(),closed.end(),next)!=closed.end()))
			{
				 
				Node  temp(next,now.dept+1,now.theWay+'1');
				open.push(temp);
				closed.push_back(next);
			}
		}
		if(now.moveRight(next))
		{
			if(!( find(closed.begin(),closed.end(),next)!=closed.end()))
			{
				 
				Node temp(next,now.dept+1,now.theWay+'2');
			
				open.push(temp);
			    closed.push_back(next);
			}
		}
		 if(now.moveUp(next))
		{
			if(!( find(closed.begin(),closed.end(),next)!=closed.end()))
			{
			 
				Node temp(next,now.dept+1,now.theWay+'3');
					 
				open.push(temp);
				closed.push_back(next);
			}
		}
		if(now.moveDown(next))
		{
			if(!( find(closed.begin(),closed.end(),next)!=closed.end()))
			{
				 
				Node  temp(next,now.dept+1,now.theWay+'4');
				 
				open.push(temp);
				closed.push_back(next);
			}
		}

		
		
	}
}
int main()
{
	 NineBox *myNineBox=new NineBox();
	 myNineBox->run();
	return 0;
}

    原文作者:九宫格问题
    原文地址: https://blog.csdn.net/mazheng1989/article/details/6916101
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞