#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; } int i; for(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("Eight_result.txt",ios::ate|ios::app); fout<<total++<<"t"; for(int i=0;i<Num;) fout<<" "<<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 Type> class TList; //线性表前视定义 template<class Type> class TNode //线性表结点类模板 { friend class TList<Type>; public: TNode(){} TNode(const Type& dat); private: TNode<Type>* Next; Type Data; }; template<class Type> 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<Type> *First,*Last; //数据成员,线性表首、尾指针 int Length; //数据成员,线性表长度 }; template<class Type> int TList<Type>::Append(const Type& T) { Insert(T,Length); return 1; } template<class Type> int TList<Type>::Insert(const Type& T,int k) { TNode<Type> *p=new TNode<Type>; 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<Type> *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<class Type> Type TList<Type>::GetData(int k) { TNode<Type> *p=First; while(k-->0) p=p->Next; return p->Data; } template<class Type> void TList<Type>::SetData(const Type& T,int k) { TNode<Type> *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<TBFS> &L); int Repeat(TList<TBFS> &L); int Find(); }; void TBFS::Printl(TList<TBFS> &L) { TBFS T=*this; if(T.last==-1) return; else { T=L.GetData(T.last); T.Printl(L); T.Printf(); } } int TBFS::Repeat(TList<TBFS> &L) { int n=L.Getlen(); int i; for(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<TBFS> 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++; } }4.广度优先搜索法的缺点
class TDBFS:public TEight { public: TDBFS(){} TDBFS(char *fname):TEight(fname){} virtual void Search(); private: void Printp(TList<TDBFS> &L); void Printb(TList<TDBFS> &L); int Repeat(TList<TDBFS> &L); }; void TDBFS::Printp(TList<TDBFS> &L) { TDBFS T=*this; if(T.last==-1) return; else { T=L.GetData(T.last); T.Printp(L); T.Printf(); } } void TDBFS::Printb(TList<TDBFS> &L) { TDBFS T=*this; while(T.last>-1) { T=L.GetData(T.last); T.Printf(); } } int TDBFS::Repeat(TList<TDBFS> &L) { int n=L.Getlen(); int i; for(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<TDBFS> 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 *fname1,char *fname2); //带参数构造函数 virtual void Search(); //A*搜索法 private: int f,g,h; //估价函数 int r[Num]; //存储状态中各个数字位置的辅助数组 static int s[Num]; //存储目标状态中各个数字位置的辅助数组 static int e[]; //存储各个数字相对距离的辅助数组 void Printl(TList<TAstar> L); //成员函数,输出搜索路径 int Expend(int i); //成员函数,A*算法的状态扩展函数 int Calcuf(); //成员函数,计算估价函数 void Sort(TList<TAstar>& L,int k); //成员函数,将新扩展结点按f从小到大顺序插入待扩展结点队列 int Repeat(TList<TAstar> &L); //成员函数,检查结点是否重复 }; int TAstar::s[Num],TAstar::e[Num*Num]; TAstar::TAstar(char *fname1,char *fname2):TEight(fname1) { for(int i=0;i<Num;) { r[p[i]]=i; //存储初始状态个个数字的位置 s[q[i]]=i++; //存储目标状态个个数字的位置 } ifstream fin; fin.open(fname2,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<TAstar> 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<TAstar>& 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<TAstar> &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<TAstar> 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.Printf(); //输出目标状态 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++; //一个结点不能再扩展,队列头指针指向下一结点 } }
A*算法的测试:
int main() { TAstar aStar("eight.txt","eight_dis.txt"); aStar.Search(); return 0; }eight.txt文件中的数据(初始态和目标态):
4 3 2 3 2 1 2 1 0