A星八数码
来源:互联网 发布:php简单的测试例子 编辑:程序博客网 时间:2024/05/16 10:13
#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星八数码
- 八数码(A星)
- 八数码A*搜索
- A*,八数码
- hdu1043【八数码】【A*】
- 八数码 A*算法
- a*八数码(有问题)
- 八数码(A* 735ms)
- 八数码游戏 A*算法
- 八数码问题A*算法
- hdu 1043 八数码 A*
- 八数码问题-A*算法
- poj-1077 八数码 【a*】
- 八数码之A*解决方法
- 八数码问题--A*算法
- A*搜索 - 八数码问题
- 八数码难题 codevs1225 a*
- 【宽搜】【A星】八数码难题 WikiOI 1225 Astar
- 详解预处理器宏的几个特征及其应用
- Android.mk详细
- 下载图片
- java的反射机制说明.txt
- EXT2的磁盘数据结构
- A星八数码
- hdu 1012
- Swing之JTable篇设置表格选中行的前景色和背景色
- 努力!+++come on!
- dma_alloc_writecombine
- ubuntu中获取命令的源代码
- Swing开发之JComboBox篇
- Linux笔记——shell补充:参数传递&函数等
- 嵌入式新手入门篇