pku acm 1077

非常經典的8數碼問題,主要採用的算法是人工智能中的“有序搜索算法”,也有人稱之爲A算法。


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
using namespace std;

const int LEN = 9;
struct  PStatus
{
	string pos;//位置信息
	int index;//'x'的座標位置
	PStatus *parent;//指向父狀態
	char direction;//l,r,u,d

	int height;//高度
	int f;//f值
};

PStatus bStatus;
PStatus gStatus = {"12345678x"};

int getWrongPoses(string pos)//錯放棋子個數
{
	int sum = 0;
	for (int i = 0; i < pos.size(); ++i)	
		if (gStatus.pos[i] != pos[i])
			sum++;	
	return sum;
}

bool cmp1(PStatus* first,PStatus* second)
{
	int r = first->pos.compare(second->pos);
	if (r < 0)return false;
	if (r > 0)return true;
	return false;
}
set<PStatus*,bool (*)(PStatus* ,PStatus* )> closed(cmp1);

bool cmp2(PStatus* first,PStatus* second)
{
	if (first->f < second->f)return true;
	if (first->f > second->f)return false;
	return false;
}
multiset<PStatus*,bool (*)(PStatus* ,PStatus* )> open(cmp2);

bool isInClosed(PStatus* status)
{
	if (closed.find(status) != closed.end())return true;	
	return false;
}

bool isInOpen(PStatus* status)
{
	multiset<PStatus*,bool (*)(PStatus* ,PStatus* )>::iterator it = open.begin();
	for (; it != open.end(); ++it)
		if (status->pos == (*it)->pos)
			return true;
	return false;
}

string bfs()
{
	PStatus *ps,*np;
	int i;
	open.insert(&bStatus);

	while (open.size() > 0)
	{
		ps = *open.begin();
		if (ps->pos == gStatus.pos)//找到答案
		{
			string result = "";
			while(ps != NULL)
			{
				if (ps->direction != 'z')
					result = ps->direction + result;
				ps = ps->parent;
			}
			return result;
		}		

		open.erase(open.begin());
		closed.insert(ps);
		
		for (i = 0; i < 4; ++i)
		{
			switch(i)
			{
			case 0://left
				if (ps->direction != 'r' && ps->index%3 != 0)
				{
					np = new PStatus;
					np->pos = ps->pos;
					swap(np->pos[ps->index], np->pos[ps->index-1]);
					if (!isInClosed(np) && !isInOpen(np))
					{
						np->parent = ps;
						np->index = ps->index - 1;
						np->direction = 'l';

						//np->height = ps->height + 1;
						//np->f = np->height + getWrongPoses(np->pos);
						np->f = getWrongPoses(np->pos);

						open.insert(np);
					}
					else
						delete np;					
				}
				break;
			case 1://right
				if (ps->direction != 'l' && ps->index%3 != 2)
				{
					np = new PStatus;
					np->pos = ps->pos;
					swap(np->pos[ps->index], np->pos[ps->index+1]);
					if (!isInClosed(np) && !isInOpen(np))
					{
						np->parent = ps;
						np->index = ps->index+1;
						np->direction = 'r';

						//np->height = ps->height + 1;
						//np->f = np->height + getWrongPoses(np->pos);
						np->f = getWrongPoses(np->pos);

						open.insert(np);
					}
					else
						delete np;	
				}
				break;
			case 2://up
				if (ps->direction != 'd' && (ps->index - ps->index%3) > 2)
				{
					np = new PStatus;
					np->pos = ps->pos;
					swap(np->pos[ps->index], np->pos[ps->index-3]);
					if (!isInClosed(np) && !isInOpen(np))
					{
						np->parent = ps;
						np->index = ps->index - 3;
						np->direction = 'u';

						//np->height = ps->height + 1;
						//np->f = np->height + getWrongPoses(np->pos);
						np->f = getWrongPoses(np->pos);

						open.insert(np);
					}
					else
						delete np;	
				}
				break;
			case 3://down
				if (ps->direction != 'u' && ps->index  < 6)
				{
					np = new PStatus;
					np->pos = ps->pos;
					swap(np->pos[ps->index], np->pos[ps->index+3]);
					if (!isInClosed(np) && !isInOpen(np))
					{
						np->parent = ps;
						np->index = ps->index +3;
						np->direction = 'd';

						//np->height = ps->height + 1;
						//np->f = np->height + getWrongPoses(np->pos);
						np->f = getWrongPoses(np->pos);

						open.insert(np);
					}
					else
						delete np;	
				}
				break;
			}
		}		
	}

	return "unsolvable";
}


//兩個狀態之間是否可達,可以通過計算兩者的逆序值,若兩者奇偶性相同則可達,不然兩個狀態不可達
bool solvable(string pos,int index)
{
	pos.erase(index,1);
	int sum = 0;
	for (int i = 1; i < pos.size(); ++i)
	{
		for (int j = 0; j < i; ++j)
			if (pos[i] < pos[j])
				sum += 1;		
	}
	if (sum%2 == 0)return true;
	else return false;
}

int main()
{
	freopen("in.txt","r",stdin);
	char ch;
	for (int i = 0; i < LEN; ++i)
	{
		cin>>ch;
		bStatus.pos += ch;
		if (ch == 'x')bStatus.index = i;		
	}		

	if(!solvable(bStatus.pos,bStatus.index))
		cout<<"unsolvable"<<endl;
	else
	{
		bStatus.parent = NULL;
		bStatus.direction = 'z';//沒有方向
		bStatus.height = 0;
		bStatus.f = getWrongPoses(bStatus.pos) + bStatus.height;
		cout<<bfs()<<endl;
	}
	
}

測試數據

2 3 4 1 5 x 7 6 8

1 2 3 7 6 4 8 x 5

1 2 3 7 x 4 8 6 5

1 2 3 4 5 6 7 x 8

1 2 7 4 5 6 3 8 x


下面這個版本速度太慢,但是對於STL的學習還是不錯的。

//#include <iostream>
//#include <cstdio>
//#include <algorithm>
//#include <list>
//#include <string>
//using namespace std;
//
//const int LEN = 9;
//struct  PStatus
//{
//	string pos;//位置信息
//	int index;//'x'的座標位置
//	PStatus *parent;//指向父狀態
//	char direction;//l,r,u,d
//};
//
//template<class T1,class T2,class T3>
//struct fcmp:public std::binary_function<T1,T2,T3>
//{
//	T3 operator()(T1 first, T2 second) const
//	{
//		return first->pos == second->pos;
//	}
//};
//
//PStatus bStatus;
//PStatus gStatus = {"12345678x"};
//list<PStatus*> open,closed;
//
//bool isInClosed(PStatus* status)
//{
//	list<PStatus*>::iterator it = find_if(closed.begin(),closed.end(),
//		bind2nd(fcmp<PStatus*, PStatus*,bool>(), status));
//	if (it != closed.end())return true;
//	return false;
//}
//
//bool isInOpen(PStatus* status)
//{
//	list<PStatus*>::iterator it = find_if(open.begin(),open.end(),
//		bind2nd(fcmp<PStatus*, PStatus*,bool>(), status));
//	if (it != open.end())return true;
//	return false;
//}
//
//void bfs()
//{
//	PStatus *ps,*np;
//	int i;
//	open.push_back(&bStatus);
//	while (open.size() > 0)
//	{
//		ps = open.front();
//		if (ps->pos == gStatus.pos)//找到答案
//		{
//			while(ps != NULL)
//			{
//				cout<<ps->direction;
//				ps = ps->parent;
//			}
//			return;
//		}		
//
//		open.pop_front();
//		closed.push_back(ps);
//
//		for (i = 0; i < 4; ++i)
//		{
//			switch(i)
//			{
//			case 0://left
//				if (ps->direction != 'r' && ps->index%3 != 0)
//				{
//					np = new PStatus;
//					np->pos = ps->pos;
//					swap(np->pos[ps->index], np->pos[ps->index-1]);
//					if (!isInClosed(np) && !isInOpen(np))
//					{
//						np->parent = ps;
//						np->index = ps->index - 1;
//						np->direction = 'l';
//
//						open.push_back(np);
//					}
//					else
//						delete np;					
//				}
//				break;
//			case 1://right
//				if (ps->direction != 'l' && ps->index%3 != 2)
//				{
//					np = new PStatus;
//					np->pos = ps->pos;
//					swap(np->pos[ps->index], np->pos[ps->index+1]);
//					if (!isInClosed(np) && !isInOpen(np))
//					{
//						np->parent = ps;
//						np->index = ps->index+1;
//						np->direction = 'r';
//
//						open.push_back(np);
//					}
//					else
//						delete np;	
//				}
//				break;
//			case 2://up
//				if (ps->direction != 'd' && (ps->index - ps->index%3) > 2)
//				{
//					np = new PStatus;
//					np->pos = ps->pos;
//					swap(np->pos[ps->index], np->pos[ps->index-3]);
//					if (!isInClosed(np) && !isInOpen(np))
//					{
//						np->parent = ps;
//						np->index = ps->index - 3;
//						np->direction = 'u';
//
//						open.push_back(np);
//					}
//					else
//						delete np;	
//				}
//				break;
//			case 3://down
//				if (ps->direction != 'u' && ps->index  < 6)
//				{
//					np = new PStatus;
//					np->pos = ps->pos;
//					swap(np->pos[ps->index], np->pos[ps->index+3]);
//					if (!isInClosed(np) && !isInOpen(np))
//					{
//						np->parent = ps;
//						np->index = ps->index +3;
//						np->direction = 'd';
//
//						open.push_back(np);
//					}
//					else
//						delete np;	
//				}
//				break;
//			}
//		}		
//	}
//
//	cout<<"unsolvable"<<endl;
//}
//
//bool solvable(string pos,int index)
//{
//	pos.erase(index,1);
//	int sum = 0;
//	for (int i = 1; i < pos.size(); ++i)
//	{
//		for (int j = 0; j < i; ++j)
//			if (pos[i] < pos[j])
//				sum += 1;		
//	}
//	if (sum%2 == 0)return true;
//	else return false;
//}
//
//int main()
//{
//	freopen("in.txt","r",stdin);
//	char ch;
//	for (int i = 0; i < LEN; ++i)
//	{
//		cin>>ch;
//		bStatus.pos += ch;
//		if (ch == 'x')bStatus.index = i;		
//	}		
//
//	if(!solvable(bStatus.pos,bStatus.index))
//		cout<<"unsolvable"<<endl;
//	else
//	{
//		bStatus.parent = NULL;
//		bStatus.direction = 'z';//沒有方向
//		bfs();
//	}
//
//}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章