八数码

来源:互联网 发布:中国商品贸易数据库 编辑:程序博客网 时间:2024/04/29 04:01
#include<iostream> 
#include<cstdlib>
#define N 1000
using namespace std;
int sum=0;
int head=0,step=0;
int m=0,ta=0;
int zuixiao[N];
char cdir[4]={'u','r','d','l'};// 方向对应字母 
char opcdir[4]={'d','l','u','r'};//反方向对应字母 
const int aim_state[9]={1,2,3,8,0,4,7,6,5};//目标状态
const int aim_loc[9]={4,0,1,2,5,8,7,6,3};//每个数字的目标位置
struct bashuma
{
int ccstate[9];
int a;
char fx;
int flag;
int pre;
int cengshu;
};
inline int Abs(int a)
{
return a>0?a:-a;//绝对值函数 
}
inline int Manh(int loc1,int loc2) 
{
return Abs(loc1/3-loc2/3)+Abs(loc1%3-loc2%3);//各列与各行之间的差的和即为该点距离它们的目标位置和为估价值
}
inline int h(int state[9])//以1—8的点的位置距离它们的目标位置和为估价值 
{
int ans=0;
for(int i=0;i<9;i++)
if(state[i])
ans+=Manh(i,aim_loc[state[i]]);
return ans;
}
inline int check(int state[9])//比较是否成功 
{
for(int i=0;i<9;i++)
if(state[i]!=aim_state[i])
    return 0;
    return 1;
}
inline bool canMove(int loc,int dir,int&nxt)//判断空格在loc位置时能否向dir方向移动,同时返回移动后的位置nxt 
{
switch(dir)
{
case 0:
nxt=loc-3;    //上 
return loc>2;
case 1:
nxt=loc+1;    //右 
return loc%3!=2;
case 2:
nxt=loc+3;
return loc<6;//下 
case 3:
nxt=loc-1;
return loc%3;//左 
}
}
bashuma chushihua(bashuma bsm[])
{
int k;
    //int bsmchushihua[9]={2,8,3,1,6,4,7,0,5};//五步即到
int bsmchushihua[9]={3,1,8,7,6,4,0,2,5};//21步
    //int bsmchushihua[9]={1,2,3,8,6,4,7,0,5};//一步即到
//int bsmchushihua[9]={1,2,3,6,0,5,7,8,4};
//int bsmchushihua[9]={0,2,3,8,1,4,7,6,4};
//int bsmchushihua[9]={2,0,3,1,8,4,7,6,5};
//int bsmchushihua[9]={1,3,4,7,8,0,6,5,2};
    for(k=0;k<9;k++)
    {
    bsm[0].ccstate[k]=bsmchushihua[k];
}
bsm[0].a=h(bsm[0].ccstate);
bsm[0].fx=0;
bsm[0].flag=1;
bsm[0].pre=-1;
bsm[0].cengshu=0;
return bsm[0];

}
void rudui1(bashuma bsm[],bashuma bsm1[],char c)
{   int k;
ta++;
for(k=0;k<9;k++)
  {
bsm1[ta].ccstate[k]=bsm[head].ccstate[k];
  }
//bsm1[ta].a=h(bsm[head].ccstate)+head;
 bsm1[ta].fx=c;
 bsm1[ta].flag=0;
 if(m==1){zuixiao[m-1]==-1;bsm1[ta].pre=zuixiao[m-1];}
 else
 {
 bsm1[ta].pre=zuixiao[m-1];}
  bsm1[ta].a=h(bsm[head].ccstate)+bsm1[bsm1[ta].pre].cengshu;//bsm1[ta].a=h(bsm[head].ccstate);
bsm1[ta].cengshu=bsm1[bsm1[ta].pre].cengshu+1;
 /*printf("\n%d",ta);
for(k=0;k<9;k++)
  {
 
if(k%3==0)printf("\n");
printf("%d  ",bsm1[ta].ccstate[k]);

  }
printf("\n",ta-1);*/


}
void rudui(bashuma bsm[],bashuma bsm1[],int i)
{   
head++;
int k;
for(k=0;k<9;k++)
  {
bsm[head].ccstate[k]=bsm1[i].ccstate[k];
  }
 bsm[head].a=bsm1[i].a;
 bsm[head].fx=bsm1[i].fx;
 bsm[head].pre=i;
  /* printf("\n%d",head);
for(k=0;k<9;k++)
  {
 
if(k%3==0)printf("\n");
printf("%d  ",bsm1[head].ccstate[k]);

  }
printf("\n",head);*/


}
int min(bashuma bsm[])//找到最小的 
{
    
  int smallest;
int i;
   smallest = 100000;
    for( i =1; i <=ta; i++)
{   if(bsm[i].flag==1)continue;
if(smallest > bsm[i].a)
smallest = bsm[i].a;
  }
  for ( i = 1; i <=ta; i++)
{ if(bsm[i].flag==1)continue;
if(smallest ==bsm[i].a)
return i;
  }

}
int locate(bashuma bsm[])
{   int k;
for(k=0;k<9;k++)
  {
if(bsm[head].ccstate[k]==0)
return k;
  }
}
int bianli1(bashuma bsm[],bashuma bsm1[])
{
int k,j,l;
for(k=0;k<=ta;k++)
{
l=0;
for(j=0;j<9;j++)
{
if(bsm1[k].ccstate[j]==bsm[head].ccstate[j])
l++;
}
if(l==9)
   return 0;
else return 1;
}
}
int pp(bashuma bsm[],bashuma bsm1[])
{   int c,k,j,flag,n,a;
    //与终极目标相符返回结束
int nxt,now; 
while(!check(bsm[head].ccstate))
{
now=locate(bsm);
for(int dir=0;dir<4;dir++)//空格可以往四个方向移动
{
if(head==0)
if(canMove(now,dir,nxt)) 
{
bsm[head].ccstate[now]=bsm[head].ccstate[nxt];
bsm[head].ccstate[nxt]=0;
rudui1(bsm,bsm1,cdir[dir]);
//还原数组,进行下一个方向的变换 
bsm[head].ccstate[nxt]=bsm[head].ccstate[now];
bsm[head].ccstate[now]=0;

}
if((head!=0)&&(bsm[head].fx!=opcdir[dir])&&canMove(now,dir,nxt))
{
bsm[head].ccstate[now]=bsm[head].ccstate[nxt];
bsm[head].ccstate[nxt]=0;
if(bianli1(bsm,bsm1)){rudui1(bsm,bsm1,cdir[dir]);}
bsm[head].ccstate[nxt]=bsm[head].ccstate[now];
bsm[head].ccstate[now]=0;
}

}
zuixiao[m]=min(bsm1);
a=zuixiao[m];
   bsm1[a].flag=1;
m++;
//A*算法找到值最小的步骤  入队head++ 作为扩展节点,否则不入队
rudui(bsm,bsm1,a);
}
if(check(bsm[head].ccstate))
return 1;
else return 0;


}
void shuchu(bashuma bsm[],int i)
{   int k;
if(bsm[i].pre==-1)
return;
if(bsm[i].pre!=-1)
shuchu(bsm,bsm[i].pre);
printf("\n");
for(k=0;k<9;k++)
  {
 
if(k%3==0)printf("\n");
printf("%d  ",bsm[i].ccstate[k]);
  }
step++;
printf("\n");
}


int main()
{
//...
return 0;


}
/*****************************************        题目    ****************************************************
八数码难题
   3×3九宫棋盘,放置数码为1 - 8的8个棋牌,剩下一个空格,只能通过棋牌向空格的移动来改变棋盘的布局。
求解的问题——给定初始布局(即初始状态)和目标布局(即目标状态),如何移动棋牌才能从初始布局到达目标布局 
解答路径——就是一个合法的走步序列 
用宽度优先搜索方法解决该问题:
 为问题状态的表示建立数据结构:3×3的一个矩阵,
* 矩阵元素S ij∈{0,1,…,8};其中1≤i,j≤3,
* 数字0指示空格,
* 数字1 - 8指示相应棋牌。
 初始状态S0:             2     3      目标状态Sg:1  2  3
                          1  8  4           8  0  4
                       7  6  5                  7  6  5
 制定操作算子集:
* 直观方法——为每个棋牌制定一套可能的走步:左、上、右、下四种移动。这样就需32个操作算子。
*简易方法——仅为空格制定这4种走步,因为只有紧靠空格的棋牌才能移动。
* 空格移动的唯一约束是不能移出棋盘。 
****************************************      A*算法应用     *****************************************************
    估价函数:f(n)=d(n)+w(n)
其中:d(n)为n的深度   w(n)为不在位的棋子数
根据f(n)的大小全局择优搜索
 取h(n)=w(n),则有w(n)≤h*(n),h(n)满足A*算法的限制条件
 在编程中注意:
 1:深度和前驱节点的记录。(队列队首元素和队尾元素的下标的作用。)
 2:采用宽度优先搜索,再根据A*算法,从open表中选出相对函数值最小的节点进行拓展。
 注意深度优先搜索不适合,可能选择的一个分支到最后无解。
 3:递归算法应用
 
 
*/



0 0
原创粉丝点击