http://www.dakaren.com/blog/post/3.html
八数码问题
一.八数码问题#define Num 9 class TEight { public: TEight(){} TEight(char *fname); virtual void Search()=0; protected: int p[Num]; int last,spac; static int q[Num],d[],total; void Printf(); bool operator==(const TEight &T); bool Extend(int i); }; int TEight::q[Num]; int TEight::d[]={1,3,-1,-3}; int TEight::total=0; TEight::TEight(char *fname) { ifstream fin; fin.open(fname,ios::in | ios::nocreate); if(!fin) { cout<<"不能打开数据文件!"<<endl; return; } for(int i=0;i<num;) fin>>p[i++]; fin>>spac; for(i=0;i<num;) fin>>q[i++]; fin.close(); last=-1; total=0; } void TEight::Printf() { ofstream fout; fout.open(".\Eightr.txt",ios::ate); fout<<setw(4)<<total++<<"t"; for(int i=0;i<num;) fout<<setw(2)<<p[i++]; fout<<endl; fout.close(); } bool TEight::operator==(const TEight &T) { for(int i=0;i<num;) if(T.p[i]!=p[i++]) return 0; return 1; } bool TEight::Extend(int i) { if(i==0 && spac%3==2 || i==1 && spac>5 || i==2 && spac%3==0 || i==3 && spac<3) return 0; int temp=spac; spac+=d[i]; p[temp]=p[spac]; p[spac]=0; return 1; }
template class TList; //线性表前视定义 template class TNode //线性表结点类模板 { friend class TList; public: TNode(){} TNode(const Type& dat); private: TNode* Next; Type Data; }; template class TList { public: TList(){Last=First=0;Length=0;} //构造函数 int Getlen()const{return Length;} //成员函数,返回线性表长度 int Append(const Type& T); //成员函数,从表尾加入结点 int Insert(const Type& T,int k); //成员函数,插入结点 Type GetData(int i); //成员函数,返回结点数据成员 void SetData(const Type& T,int k); //成员函数,设置结点数据成员 private: TNode *First,*Last; //数据成员,线性表首、尾指针 int Length; //数据成员,线性表长度 }; template int TList::Append(const Type& T) { Insert(T,Length); return 1; } template int TList::Insert(const Type& T,int k) { TNode *p=new TNode; p->Data=T; if(First) { if(k<=0) { p->Next=First; First=p; } if(k>Length-1) { Last->Next=p; Last=Last->Next; Last->Next=0; } if(k>0 && k<length) { k--; TNode *q=First; while(k-->0) q=q->Next; p->Next=q->Next; q->Next=p; } } else { First=Last=p; First->Next=Last->Next=0; } Length++; return 1; } template Type TList::GetData(int k) { TNode *p=First; while(k-->0) p=p->Next; return p->Data; } template void TList::SetData(const Type& T,int k) { TNode *p=First; while(k-->0) p=p->Next; p->Data=T; }
class TBFS:public TEight { public: TBFS(){} TBFS(char *fname):TEight(fname){} virtual void Search(); private: void Printl(TList &L); int Repeat(TList &L); int Find(); }; void TBFS::Printl(TList &L) { TBFS T=*this; if(T.last==-1) return; else { T=L.GetData(T.last); T.Printl(L); T.Printf(); } } int TBFS::Repeat(TList &L) { int n=L.Getlen(); for(int i=0;i<n;i++) if(L.GetData(i)==*this) break; return i; } int TBFS::Find() { for(int i=0;i<num;) if(p[i]!=q[i++]) return 0; return 1; } void TBFS::Search() { TBFS T=*this; TList L; L.Append(T); int head=0,tail=0; while(head<=tail) { for(int i=0;i<4;i++) { T=L.GetData(head); if(T.Extend(i) && T.Repeat(L)>tail) { T.last=head; L.Append(T); tail++; } if(T.Find()) { T.Printl(L); T.Printf(); return; } } head++; } }
class TDBFS:public TEight { public: TDBFS(){} TDBFS(char *fname):TEight(fname){} virtual void Search(); private: void Printp(TList &L); void Printb(TList &L); int Repeat(TList &L); }; void TDBFS::Printp(TList &L) { TDBFS T=*this; if(T.last==-1) return; else { T=L.GetData(T.last); T.Printp(L); T.Printf(); } } void TDBFS::Printb(TList &L) { TDBFS T=*this; while(T.last>-1) { T=L.GetData(T.last); T.Printf(); } } int TDBFS::Repeat(TList &L) { int n=L.Getlen(); for(int i=0;i<n;) if(L.GetData(i++)==*this) break; return i; } void TDBFS::Search() { TDBFS T1=*this; TDBFS T2; for(int i=0;i<num;i++) { T2.p[i]=q[i]; if(q[i]==0) T2.spac=i; } T2.last=-1; TList L1,L2; L1.Append(T1); L2.Append(T2); int head1=0,tail1=0,head2=0,tail2=0; while(head1<=tail1 || head2<=tail2) { for(int i=0;i<4;i++) { T1=L1.GetData(head1); if(T1.Extend(i) && T1.Repeat(L1)>tail1) { T1.last=head1; L1.Append(T1); tail1++; } int m=T1.Repeat(L2); if(m<tail2) { T1.Printp(L1); T1.Printf(); T2=L2.GetData(m); T2.Printb(L2); return; } } head1++; for(i=0;i<4;i++) { T2=L2.GetData(head2); if(T2.Extend(i) && T2.Repeat(L2)>tail2) { T2.last=head2; L2.Append(T2); tail2++; } int m=T2.Repeat(L1); if(m<tail1) { T1=L1.GetData(m); T1.Printb(L1); T1.Printf(); T2.Printp(L2); return; } } head2++; } }
class TAstar:public TEight { public: TAstar(){} //构造函数 TAstar(char *fname); //带参数构造函数 virtual void Search(); //A*搜索法 private: int f,g,h; //估价函数 int r[Num]; //存储状态中各个数字位置的辅助数组 static int s[Num]; //存储目标状态中各个数字位置的辅助数组 static int e[]; //存储各个数字相对距离的辅助数组 void Printl(TList L); //成员函数,输出搜索路径 int Expend(int i); //成员函数,A*算法的状态扩展函数 int Calcuf(); //成员函数,计算估价函数 void Sort(TList& L,int k); //成员函数,将新扩展结点按f从小到大 //顺序插入待扩展结点队列 int Repeat(TList &L); //成员函数,检查结点是否重复 }; int TAstar::s[Num],TAstar::e[Num*Num]; TAstar::TAstar(char *fname):TEight(fname) { for(int i=0;i<num;) { r[p[i]]=i; //存储初始状态个个数字的位置 s[q[i]]=i++; //存储目标状态个个数字的位置 } ifstream fin; fin.open(".\Eightd.txt",ios::in | ios::nocreate);//打开数据文件 if(!fin) { cout<<"不能打开数据文件!"<<endl; return; } for(i=0;i<num*num;i++) 读入各个数字相对距离值="" fin>>e[i]; fin.close(); f=g=h=0; //估价函数初始值 } void TAstar::Printl(TList L) { TAstar T=*this; if(T.last==-1) return; else { T=L.GetData(T.last); T.Printl(L); T.Printf(); } } int TAstar::Expend(int i) { if(Extend(i)) //结点可扩展 { int temp=r[p[r[0]]]; //改变状态后数字位置变化,存储改变后的位置 r[p[r[0]]]=r[0]; r[0]=temp; return 1; } return 0; } int TAstar::Calcuf() { h=0; for(int i=0;i<num;i++) 计算估价函数的h h+=e[Num*r[i]+s[i]]; return ++g+h; } void TAstar::Sort(TList& L,int k) { int n=L.Getlen(); for(int i=k+1;i<n;i++) { TAstar T=L.GetData(i); if(this->f<=T.f) break; } L.Insert(*this,i); } int TAstar::Repeat(TList &L) { int n=L.Getlen(); for(int i=0;i<n;i++) if(L.GetData(i)==*this) break; return i; } void TAstar::Search() { TAstar T=*this; //初始结点 T.f=T.Calcuf(); //初始结点的估价函数 TList L; //建立队列 L.Append(T); //初始结点入队 int head=0,tail=0; //队列头和尾指针 while(head<=tail) //队列不空则循环 { for(int i=0;i<4;i++) //空格可能移动方向 { T=L.GetData(head); //去队列头结点 if(T.h==0) //是目标结点 { T.Printl(L);//输出搜索路径 T.Print(); //输出目标状态 return; //结束 } if(T.Expend(i)) //若结点可扩展 { int k=T.Repeat(L); //返回与已扩展结点重复的序号 if(k<head) 如果是不能扩展的结点 continue; //丢弃 T.last=head; //不是不能扩展的结点,记录父结点 T.f=T.Calcuf(); //计算f if(k<=tail) //新结点与可扩展结点重复 { TAstar Temp=L.GetData(k); if(Temp.g>T.g) //比较两结点g值 L.SetData(T,k); //保留g值小的 continue; } T.Sort(L,head) ; //新结点插入可扩展结点队列 tail++; //队列尾指针后移 } } head++; //一个结点不能再扩展,队列头指针指向下一结点 } }
#include #include /* \Author:Kenny wong * \Email:huangweilook@21cn.com * \version:0.1 * \Date:2006-11-26 * \bref:八数码问题A*算法解法 */ class node { public: int data[9]; int zeroPos; int distanceToOri; int distanceToDis; node *parent; public: node(){} node(int *data, int zeroPos, node *parent, int disToOri, int disToDis) :zeroPos(zeroPos),parent(parent),distanceToOri(disToOri), distanceToDis(disToDis) { memcpy(this -> data, data,sizeof(int)*9); } void setParent(node *parent) { this -> parent = parent; } int getRight() { return distanceToDis + distanceToOri; } }; class AStar { private: std::vector openList; std::vector closeList; int grid[9];//当前棋盘 int target[9];//目标棋盘 int zeroPos; int finZeroPos; typedef void (AStar::*p)(int*,int); p direction[4]; public: AStar(int *grid,int *target,int pos,int finPos) { memcpy(this -> grid, grid, sizeof(int)*9); memcpy(this -> target, target, sizeof(int)*9); zeroPos = pos; finZeroPos = finPos; direction[0] = &AStar::up; direction[1] = &AStar::down; direction[2] = &AStar::left; direction[3] = &AStar::right; } ~AStar(){} void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } void up(int *input,int pos) { memcpy(grid,input,sizeof(int)*9); zeroPos = pos; swap(&grid[zeroPos], &grid[zeroPos - 3]); zeroPos -= 3; } void down(int *input,int pos) { memcpy(grid,input,sizeof(int)*9); zeroPos = pos; swap(&grid[zeroPos], &grid[zeroPos + 3]); zeroPos += 3; } void left(int *input,int pos) { memcpy(grid,input,sizeof(int)*9); zeroPos = pos; swap(&grid[zeroPos], &grid[zeroPos - 1]); zeroPos -= 1; } void right(int *input,int pos) { memcpy(grid,input,sizeof(int)*9); zeroPos = pos; swap(&grid[zeroPos], &grid[zeroPos + 1]); zeroPos += 1; } bool check(int i,int Pos) { if(Pos - 3 < 0)//第一行 { switch(Pos) { case 0: if( i == 0 || i == 2) return false; break; case 1: if( i == 0) return false; break; case 2: if( i == 0 || i == 3) return false; break; default: break; } } if(Pos - 3 >= 3)//第三行 { switch(Pos) { case 6: if( i == 1 || i == 2) return false; break; case 7: if( i == 1) return false; break; case 8: if( i == 1 || i == 3) return false; break; default: break; } } else { switch(Pos) { case 3: if( i == 2 ) return false; break; case 5: if( i == 3 ) return false; break; default: break; } } return true; } bool complete() { } node *findNext()//寻找下一个待处理结点 { std::vector::iterator it = openList.begin(); node *result = NULL; //printf("%d\n",openList.size()); if(openList.size() == 1) { result = *it; addToClose(result); openList.clear(); } if(openList.size() > 1) { ++it; std::vector::iterator end = openList.end(); std::vector::iterator minNode = openList.begin(); int minRight = (*minNode) -> getRight(); for( ; it != end; ++it) { int cur = (*it) -> getRight(); if(cur < minRight) { minRight = cur; minNode = it; } } result = *minNode; addToClose(result); openList.erase(minNode); } return result; } void addToClose(node *n) { closeList.push_back(n); } void addToOpen(node *n) { openList.push_back(n); } void processCur(node *cur)//处理当前结点 { for(int i = 0 ; i < 4; ++i) { //检测是否可达 if(check(i,cur -> zeroPos)) { (this ->* direction[i])(cur -> data,cur -> zeroPos); node *tem1 = createNode(); //检测是否在closeList中 if(!inCloseList(tem1)) { node *tem2 = NULL; //检测是否在openList中 if( (tem2 = findinOpenList(tem1)) == NULL) { tem1 -> distanceToOri = cur -> distanceToOri + calDistance(); tem1 -> distanceToDis = calDistanceToDis(); tem1 -> parent = cur; openList.push_back(tem1); } else { int temToOri = cur -> distanceToOri + calDistance();//计算经过当前点到达那个点的距离 if(temToOri < tem2 -> distanceToOri)//如果经过当前点到那个点更好 { tem2 -> parent = cur; tem2 -> distanceToOri = temToOri; tem2 -> distanceToDis = calDistanceToDis(); } } } } else { continue; } } } int calDistanceToDis() { int result = 0; for(int i = 0; i < 9; ++i) if(grid[i] == target[i]) ++result; return result; } int calDistance() { return 1; } node *createNode() { return new node(grid,zeroPos,NULL,0,0); } bool inCloseList(node *_node) { std::vector::iterator it = closeList.begin(); std::vector::iterator end = closeList.end(); for( ; it != end; ++it) if(memcmp(_node -> data, (*it) -> data,sizeof(int)*9) == 0 && _node -> zeroPos == (*it) -> zeroPos) return true; return false; } node *findinOpenList(node *_node) { std::vector::iterator it = openList.begin(); std::vector::iterator end = openList.end(); for( ; it != end; ++it) if(memcmp(_node -> data, (*it) -> data,sizeof(int)*9) == 0 && _node -> zeroPos == (*it) -> zeroPos) return *it; return NULL; } void begin() { node *ori = new node(grid,zeroPos,NULL,0,0); addToOpen(ori); node *distination = NULL; node *finish = new node(target,finZeroPos,NULL,0,0); int first[9]; memcpy(first,grid,sizeof(int)*9); while(openList.size() > 0) { if( (distination = findinOpenList(finish)) != NULL) { break; } node *temp = findNext(); if(temp != NULL) processCur(temp); } std::vector path; if(distination != NULL && distination -> parent != NULL) { node *temp = distination; while(temp -> parent != NULL) { path.push_back(temp -> data); temp = temp -> parent; } } path.push_back(first); std::vector::iterator it = path.end(); --it; std::vector::iterator begin = path.begin(); for( ; it != begin; --it) { for(int i = 0; i < 9; ++i) { printf(" %d",(*it)[i]); if( (i + 1) % 3 == 0) printf("\n"); } printf("\n"); } for(int i = 0; i < 9; ++i) { printf(" %d",(*it)[i]); if( (i + 1) % 3 == 0) printf("\n"); } } }; int main() { int ori[9] = {1,2,5,7,6,4,0,8,3}; int tar[9] = {7,1,5,8,2,4,6,0,3}; AStar A(ori,tar,6,7); A.begin(); return 0; }