A星八数码

#include<iostream>
#include<algorithm>
using namespace std;
struct node{
	char num[9];
	int gvalue;
	int hvalue;
	int fvalue;
	char action;
	node *parent;
	node *next;
};
node *openlist,*closelist,*bestnode;
char start[9];
char target[]={'1','2','3','4','5','6','7','8','x'};
bool isEmpty(node *p){
	if(p->next==NULL) return true;
	return false;
}
bool isSolved(){
	int s,t,i,j;
	s=t=0;
	for(i=0;i<9;i++)
		for(j=i;j>=0;j--){
			if((start[i]<start[j])&&start[i]!='x'&&start[j]!='x') s++;
			if((target[i]<target[j])&&target[i]!='x'&&target[j]!='x') t++;
			}
	if((s%2)==(t%2)) return true;
	return false;
}
void print_result(node* p){
	if(p!=NULL){
		print_result(p->parent);
		cout<<p->action;
		}
}
int diffnum(node *p){
	int i,count=0;
	for(i=0;i<9;i++)
       		if(p->num[i]!=target[i]) count++;
	return count;	
}
int findX(char num[]){
	int i;
	for(i=0;i<9;i++)
		if(num[i]=='x') return i;
}
void move_up(node *&p){
	int pos=findX(p->num);
	if(pos>2) {swap(p->num[pos],p->num[pos-3]);p->action='u';return;}
	return ;
	}
void move_down(node *&p){
	int pos=findX(p->num);
	if(pos<6) {swap(p->num[pos],p->num[pos+3]);p->action='d';return;}
	return;
}
void move_left(node *&p){
	int pos=findX(p->num);
	if(pos!=0&&pos!=3&&pos!=6){swap(p->num[pos],p->num[pos-1]);p->action='l';return;}
	return;
}
void move_right(node *&p){
	int pos=findX(p->num);
	if(pos!=2&&pos!=5&&pos!=8){swap(p->num[pos],p->num[pos+1]);p->action='r';return;}
	return;
}
void operate(node *&p,int op){
	switch(op){
		case 1:move_up(p);break;
		case 2:move_down(p);break;
		case 3:move_left(p);break;
		case 4:move_right(p);break;
		default:return;
	}
}
void expand(node* p){
	int op,i;
	node* pNode;
	node* p1;
	for(op=1;op<=4;op++){
		pNode=new node;
		for(i=0;i<9;i++)
			pNode->num[i]=p->num[i];
		operate(pNode,op);	
		pNode->gvalue=p->gvalue+1;
		pNode->hvalue=diffnum(pNode);
		pNode->fvalue=pNode->gvalue+pNode->hvalue;
		pNode->parent=p;
		pNode->next=NULL;
		if(bestnode==NULL) {bestnode=pNode;bestnode->next=NULL;}
			else {pNode->next=bestnode;bestnode=pNode;}
		}
}
struct node* openlist_insert(node *p){
	node* temp=openlist;
	node* pre=openlist;
	if(temp==NULL) {openlist=p;openlist->next=NULL;return openlist;}
	while(temp!=NULL){
		if(p->fvalue>temp->fvalue){
			pre=temp;
			temp=temp->next;
			}
		else if(pre==temp){p->next=temp;return p;}
			else {pre->next=p;p->next=temp;return openlist;}
	}
	pre->next=p;p->next=NULL;
	return openlist;
	}
struct node* Del(node* p,node* pList){
		node* temp=pList;
		node* pre=pList;
		int i,count=0;
		while(temp!=NULL){
			count=0;
			for(i=0;i<9;i++)
				if(p->num[i]==temp->num[i]) count++;
			if(count==9) {
				if(temp==pList) {pList=pList->next;delete temp;return pList;}
				else
				{pre->next=temp->next;delete temp;return pList;}
					}
				else pre=temp;
			temp=temp->next;
		}
		
}
struct node *InList(node *p,node *pList){
	node *temp=pList;
	int i,k;
	while(temp!=NULL){
		k=0;
		for(i=0;i<9;i++)
			if(p->num[i]==temp->num[i]) k++;
		if(k==9) return temp;
		temp=temp->next;
	 	}
	return NULL;
}
bool IsGoal(node* p){
	int i;
	for(i=0;i<9;i++)
		if(p->num[i]!=target[i]) return false;
	return true;
}
void AStar(){
	node *n=NULL,*m=NULL,*pNode=NULL;
	closelist=NULL;	
	while(openlist!=NULL){
		n=openlist;
		if(IsGoal(n)) {print_result(n);return;}
		openlist=openlist->next;
		n->next=closelist;
		closelist=n;
		expand(n);
		while(bestnode!=NULL){
			m=bestnode;
			bestnode=bestnode->next;
			if(pNode=InList(m,openlist)){
				if(m->fvalue<pNode->fvalue){
				//	pNode->fvalue=m->fvalue;
				openlist=Del(pNode,openlist);
				openlist=openlist_insert(m);
					}
				else delete m;
				}
			else if(pNode=InList(m,closelist)){
					if(m->fvalue<pNode->fvalue){cout<<m->hvalue<<endl;
						closelist=Del(pNode,closelist);
						openlist=openlist_insert(m);
						}else delete m;
				}
			else openlist=openlist_insert(m);				
		}
}
}
int main(){
	node *p=new node;
	openlist=new node;
	int i;
	for(i=0;i<9;i++)
		cin>>start[i];
	for(i=0;i<9;i++)
		p->num[i]=start[i];
	p->gvalue=0;
	p->hvalue=diffnum(p);
	p->fvalue=p->gvalue+p->hvalue;
	p->parent=NULL;
	p->next=NULL;
	openlist=p;
	if(isSolved())
		AStar();
	else cout<<"unsolved"<<endl;
}

     用组合数学的方法可以快速地进行判断,例如SOJ 2061题 2360题中都是关于此类的问题。但八数码的判断方法比他们简单多了。

        本文用的方法是计算排列的逆序数值,以2 3 1 5 8 4 6 7 5 为例子,5表示的是空格,不计算,那么求23158467 的逆序值为 
        0 + 0 + 2 (1<2 1<3 ) + 0 + 0 + 2 ( 4<5 4<8) + 1 ( 6<8 ) + 1 ( 7<8 ) = 6 
目标状态1 2 3 4 5 6 7 8 9 的逆序自然就是0。

两个状态之间是否可达,可以通过计算两者的逆序值,若两者奇偶性相同则可达,不然两个状态不可达。

简单证明一下:
        l 和 r 操作,不会影响状态的逆序值,因为只会改变个位数(空格的位置)。 
        u和d操作是使某个位置的数字 右/左 移两位。 由于数字序列的每一次移动会使逆序值奇偶性改变,所以移动两次后奇偶性不变。
        所以 四个操作均不会影响序列的奇偶性。

参考:http://blog.csdn.net/ray58750034/article/details/599897

http://blog.csdn.net/NowCan/article/details/256116

你可能感兴趣的:(A星八数码)