您的位置:首页 > 其它

Poj1077/HDU1043(A*搜索)八数码问题

2011-05-02 18:34 169 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043

http://poj.org/problem?id=1077



题意:经典的八数码问题,问给出的一个状态能否通过移动达到一个目标状态,如果能就输出一个可行的移动方式.





看过好几本书上面都有八数码问题的介绍,采用A*搜索,可一开始写的用不在目标位置上的方块个数作为h(n),可一直超时~



然后改成各个方块到目标状态的曼哈顿距离,在北大OJ上AC了,尴尬的是HDU上给了整整五倍的时间,还是超时了,今天去图书管看看新书有没有到,然后又翻了翻以前看过的一本算法书籍,看到了一个高效的估价函数,即



           h(n)=d(n)+3*g(n)



  其中d(n)为各方块到目标状态的曼哈顿矩离,g(n)为非中心的每个方块的后继是否为其目标状态的后继,如果不是,g(n)+=2,最后如果中间位置的方块和目标状态不同g(n)+=1;



结果是,原来在POJ上700+msAC的代码,时间一下子降到了32ms~ 不过郁结的是在HDU上还是花费500+ms的时间 ...





代码:

#pragma warning (disable:4786)
#include<iostream>
#include<string>
#include<queue>
#include<map>
using namespace std;
const char board[][3]={'1','2','3','4','5','6','7','8','9'};
const short next[10]={0,2,3,6,1,0,9,4,7,8};//记录目标状态后继
const short point[][2]={{0,0},{0,1},{0,2},{1,2},{2,2},{2,1},{2,0},{1,0}};
typedef struct talQ{
	char board[3][3];
	int x,y;
	int v,t;
	string s;
	bool operator < (const talQ &a)const
	{return (a.v+a.t)<(v+t);}
}Q;
Q start;
string ans;
priority_queue<Q>q;
bool flag;
short dir[][2]={{0,1},{0,-1},{1,0},{-1,0}};
char com[]="rldu";
map<int,int>mem;
short abs(short a)
{return a>0?a:-a;}
int Hash(char s[][3])
{
	int key=0;
	short i,j;
	for(i=0;i<3;i++){
		for(j=0;j<3;j++){
			key*=10;
			key+=s[i][j]-'0';
		}
	}return key;
}
short Value(char s[][3])
{
	short i,j,c=0,g=0;
	/*原估价函数
	for(i=0;i<3;i++){
		for(j=0;j<3;j++)
			c+=(abs((s[i][j]-'1')/3-i)+abs((s[i][j]-'1')%3-j));
	}
	*/
	for(i=0;i<3;i++){
		for(j=0;j<3;j++)
			c+=(abs((s[i][j]-'1')/3-i)+abs((s[i][j]-'1')%3-j));
	}
	for(i=0;i<8;i++){//增添部分
		if(s[point[(i+1)%8][0]][point[(i+1)%8][1]]!=
			next[s[point[i][0]][point[i][1]]-'0']+'0')
			g+=2;
	}
	if(s[1][1]!=board[1][1]) g++;
	return c+3*g;
}
short Caunt(char s[][3])
{
	short i,j,c=0,k;
	short tmp[9];
	k=0;
	for(i=0;i<3;i++){
		for(j=0;j<3;j++)
			if(s[i][j]!='9')
			tmp[k++]=s[i][j];
	}
	for(i=0;i<k;i++){
		for(j=i+1;j<k;j++)
			if(tmp[i]<tmp[j])c++;
	}
	return c;
}
bool Wall(int x,int y)
{
	return x<0||x>2||y<0||y>2;
}
void FindPath()
{
	short i;
	Q cur,next;
	flag=false;
	if(start.v==0){flag=true;ans="";return;}
	while(!q.empty()) q.pop();
	mem.clear();
	q.push(start);
	mem[Hash(start.board)]=1;
	while(!q.empty()){
		cur=q.top();q.pop();
		for(i=0;i<4;i++){
			next.x=cur.x+dir[i][0];
			next.y=cur.y+dir[i][1];
			if(Wall(next.x,next.y)) continue;
			next.t=cur.t+1;
			next.s=cur.s+com[i];
			memmove(next.board,cur.board,sizeof(board));
			next.board[cur.x][cur.y]=next.board[next.x][next.y];
			next.board[next.x][next.y]='9';
			next.v=Value(next.board);
			if(next.v==0) {
				flag=true;
				ans=next.s;
				return;
			}
			if(mem[Hash(next.board)]==1) continue;
			mem[Hash(next.board)]=1;
			q.push(next);
		}
	}
}
bool Read()
{
	char c[2],i,j;
	start.v=0;
	for(i=0;i<3;i++){
		for(j=0;j<3;j++){
			if(scanf("%s",c)==EOF) return false;
			if(c[0]=='x') {
				start.board[i][j]='9';
				start.x=i;start.y=j;
			}
			else start.board[i][j]=c[0];
		}
	}
	start.s="";start.t=0;start.v=Value(start.board);
	return true;
}
int main()
{
	while(Read()){
		if(Caunt(start.board)&1){
			cout<<"unsolvable"<<endl;
			continue;
		}
		FindPath();
		cout<<(flag?ans:"unsolvable")<<endl;
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: