散落一地的蓝

Welcome..............

八数码(BFS)

需要解决的问题
1.判断是否可达(错误了,任何节点都是可达的)
   解决方法:判断逆序数,若两个序列逆序数的奇偶性相同,则可达,否则不可达。
2.BFS
   解决方法:使用队列即可。
3.效率问题

   解决方法:这个方法太暴力了,最好采用启发式的搜索,以后再写。

#include <iostream>
#include <fstream>

#include <queue>
#include <stack>
#include <vector>

using namespace std;
//图的节点,0代表空格
class Node
{
	public:
		//格子
		int arc[3][3];
		//空格的位置(row,col)
		int row;
		int col;
		//父节点(closed中)
		int parent;
		//默认构造函数
		Node()
		{
			int i,j;
			for (i=0;i<3;i++)
			{
				for (j=0;j<3;j++)
				{
					arc[i][j]=0;
				}
			}
			
			parent=-1;
		}
		//一维数组构造函数
		Node(int a[])
		{
			int i,j;
			for (i=0;i<3;i++)
			{
				for (j=0;j<3;j++)
				{
					arc[i][j]=a[i*3+j];
					if (a[i*3+j]==0)
					{
						row=i;
						col=j;
					}
				}
			}
			parent=-1;
		}
		//是否可达
		bool isReach(Node n)
		{
			int i,j;
			int a[9],b[9];
			for (i=0;i<3;i++)
			{
				for (j=0;j<3;j++)
				{
					a[i*3+j]=arc[i][j];
				}
			}
			for (i=0;i<3;i++)
			{
				for (j=0;j<3;j++)
				{
					b[i*3+j]=n.arc[i][j];
				}
			}
			if (getInversionSequence(a)!=getInversionSequence(b))
			{
				return false;
			}
			return true;

		}
		//取得一个一维数组的逆序数的奇偶性,1为奇,2为偶
		int getInversionSequence(int a[])
		{
			int i,j;
			int sum=0;
			for (i=1;i<9;i++)
			{
				for (j=0;j<i;j++)
				{
					if (a[j]>a[i])
					{
						sum++;
					}
				}
			}
			if (sum%2==0)
			{
				return 2;
			} 
			else
			{
				return 1;
			}
		}
		//判断是否和N相等(仅比较arc)
		bool equalTo(Node n)
		{
			int i,j;
			for (i=0;i<3;i++)
			{
				for (j=0;j<3;j++)
				{
					if (arc[i][j]!=n.arc[i][j])
					{
						return false;
					}
				}
			}
			return true;
		}
		//空格能够向上移动
		bool canUpOne()
		{
			if (row!=0)
			{
				return true;
			}
			return false;
		}
		//空格能够向下移动
		bool canDownOne()
		{
			if (row!=2)
			{
				return true;
			}
			return false;
		}
		//空格能够向左移动
		bool canLeftOne()
		{
			if (col!=0)
			{
				return true;
			}
			return false;
		}
		//空格能够向右移动
		bool canRightOne()
		{
			if (col!=2)
			{
				return true;
			}
			return false;
		}
		//空格向上移动一个单位
		void upOne()
		{
			int t;
			t=arc[row][col];
			arc[row][col]=arc[row-1][col];
			arc[row-1][col]=t;
			row--;
		}
		//空格向下移动一个单位
		void downOne()
		{
			int t;
			t=arc[row][col];
			arc[row][col]=arc[row+1][col];
			arc[row+1][col]=t;
			row++;
		}
		//空格向左移动一个单位
		void leftOne()
		{
			int t;
			t=arc[row][col];
			arc[row][col]=arc[row][col-1];
			arc[row][col-1]=t;
			col--;
		}
		//空格向右移动一个单位
		void rightOne()
		{
			int t;
			t=arc[row][col];
			arc[row][col]=arc[row][col+1];
			arc[row][col+1]=t;
			col++;
		}
		//将节点打印至文件d:\\me.txt(要保证文件为空)
		void printArc()
		{
			ofstream f1("d:\\me.txt",ios::app);
			if(!f1)	return;
			int i,j;
			for (i=0;i<3;i++)
			{
				for (j=0;j<3;j++)
				{
					f1<<arc[i][j]<<" ";
				}
				f1<<endl;
			}
			f1<<endl;
			f1.close();
		}
};
//判断c中是否存在n节点
bool isExistInClosed(Node n,vector<Node> c)
{
	vector<Node>::iterator it = c.begin();
	while (it!=c.end())
	{
		if (n.equalTo(*it))
		{	
			return true;
		}
		it++;
	}
	return false;
}
//返回n在c中的序号
int getNnum(Node n,vector<Node> c)
{
	int i=0;
	for (i=0;i<c.size();i++)
	{
		if (c[i].equalTo(n))
		{
			return i;
		}
	}
	return 0;
}
//按节点n打印出路径,存至D盘文件me.txt
void printPath(Node n,vector<Node> c)
{
	//采用栈输出路径(反向)
	stack<Node> s;
	s.push(n);
	int p = n.parent;
	//从end节点至start节点,依次入栈
	while (p!=-1)
	{
		s.push(c[p]);
		p=c[p].parent;
	}
	//输出栈的内容,就是从start至end的路径
	while (!s.empty())
	{
		s.top().printArc();
		s.pop();
	}

	
}
//主函数
int main()
{
	queue<Node> open;
	vector<Node> closed;
	//起点节点
	int startArc[9]={2,8,3,1,0,4,7,6,5};
	//目的节点
	int endArc[9]={1,2,3,4,5,6,7,8,0};
	//int endArc[9]={1,2,3,4,5,0,7,8,6};
	Node start(startArc);
	Node end(endArc);
	//判断是否可达
	if (!start.isReach(end))
	{
		cout<<"Fail!"<<endl;
		return 0;
	}
	Node t;
	open.push(start);

	while (!open.empty())
	{
		//出队列
		t=open.front();
		open.pop();
		//如果等于end节点,打印路径,结束
		if (t.equalTo(end))
		{
			puts("Success");
			printPath(t,closed);
			return 0;
		}
		//节点加入closed
		closed.push_back(t);
		//如果空格能向上移动
		if (t.canUpOne())
		{
			Node item = t;
			item.upOne();
			//不在closed中,加入open队列
			if (!isExistInClosed(item,closed))
			{
				//找到父节点
				item.parent=getNnum(t,closed);
				open.push(item);
			}
		}
		//如果空格能向下移动
		if (t.canDownOne())
		{
			Node item = t;
			item.downOne();
			if (!isExistInClosed(item,closed))
			{
				item.parent=getNnum(t,closed);
				open.push(item);
			}
		}
		//如果空格能向左移动
		if (t.canLeftOne())
		{
			Node item = t;
			item.leftOne();
			if (!isExistInClosed(item,closed))
			{
				item.parent=getNnum(t,closed);
				open.push(item);
			}
		}
		//如果空格能向右移动
		if (t.canRightOne())
		{
			Node item = t;
			item.rightOne();
			if (!isExistInClosed(item,closed))
			{
				item.parent=getNnum(t,closed);
				open.push(item);
			}
		}
	}
	cout<<"Fail!"<<endl;
	return 0;
}


阅读更多
文章标签: iterator c class ios
个人分类: 算法
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭