简单的用c++实现的八数码问题

本文介绍了使用C++解决八数码问题的方法,通过双向队列进行广度优先搜索,判断初始状态与目标状态的奇偶性来确定解的存在性。代码中详细展示了如何遍历并更新状态,直到找到解决方案或证明无解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

真的对不住大家。刚刚由于写 代码,一符号搞错了,导致双对列只有一个起作用了。现在该好了。原谅我这个菜鸟呀。

/***

   author:zhangrong
   date:2013/4/16
   title:解决八数码问题
   the key of problem:在程序的开始阶段,根据初始化状态与目标状态的奇偶性来判断结果是否存在
      因为数字上下左右移动奇偶性不变
   //x表示空格


   u:上   d:下      l:左      r:右
   test:  input:  2 3 4  1 5 x 7 6 8

***/
#include<iostream>
#include<string.h>
#include<map>
#define NUM   500000
using namespace std;
struct POINT
{
 int s,w;
 char d;
}queue[NUM],Fqueue[NUM];                //使用双向队列

char  ans[NUM];                       //存放答案的数组
int dir[4][2]={1,0,-1,0,0,1,0,-1};//{1,0,0,1,-1,0,0,-1};   //

int main()
{
 int t[9]={100000000,10000000,1000000,100000,10000,1000,100,10,1};
 int count,m,n,i,j,k;
 map<int,int>    find;          //当find【i】=find[j] 相遇的时候说明有结果了
 char w[3][3],w2[9],finaW[9]={'1','2','3','4','5','6','7','8','x'};
 //输入初始状态的数组
 for(i=0;i<3;i++)
  for(j=0;j<3;j++)
   cin>>w[i][j];
 count=0;
 for(i=0;i<3;i++)
  for(j=0;j<3;j++)
   w2[count++]=w[i][j];
 
 //**************************
 //判断是否有解
 count=0;
 for(i=0;i<9;i++)
  for(j=0;j<i;j++)
   if(w2[i]!='x'&&w2[j]!='x'&&(w2[i]-'0')<(w2[j]-'0'))
    count++;
 k=0;
 for(i=0;i<9;i++)
  for(j=0;j<i;j++)
   if(finaW[i]!='x'&&finaW[j]!='x'&&(finaW[i]-'0')<(finaW[j]-'0'))
    k++;
 
 if((count%2==k%2))
 /*1*/{
  
  int e,s;
  int mm,nn,tt,kk,a,b,x,y,g,h,h2;  //mm ,nn,记录当前的两队列中的个数,tt,kk表示两队列目前走到哪里,ab表示空格的位置,g.h表示移动时产生的中间变量
  s=0;
  for(i=0;i<3;i++)
   for(j=0;j<3;j++)
   {
    if(w[i][j]=='x')
     s=s*10+9;
    else
     s=s*10+(w[i][j]-'0');
   }
   
   mm=nn=tt=kk=0;
         e=123456789;
   queue[mm].w=s;
   Fqueue[nn].w=e;
   find[s]=1;    //表示第1个队列的数据
   find[e]=2;  //表示第2个队列的数据
  
   bool  can=false;
   if(s==e)
   can=true;
   while(!can)
  /*2*/{
        a=0;b=0;
      int xx,yy;
    for(i=0;i<9;i++)           //找出在当前的状态下空格所处的位置
     if(queue[tt].w/t[i]%10==9)
     {a=i;break;}
             for(j=0;j<9;j++)
     if(Fqueue[kk].w/t[j]%10==9)
     {
      b=j;break;
     }

        //进行广度的遍历
    for(i=0;i<4;i++)
    /***3**/{
              x=a/3;y=a%3;
      
        xx=x+dir[i][0];
        yy=y+dir[i][1];
        if(xx<3&&yy<3&&xx>=0&&yy>=0&&can==0)
        {
         s=queue[tt].w;
         g=s/t[a];
         h2=s/t[xx*3+yy];
         g=g%10;
         h2=h2%10;
         s=s-g*t[a]-h2*t[xx*3+yy];
         s=s+h2*t[a]+g*t[xx*3+yy];
         if(find[s]!=1)
         {
          if(find[s]==2)
          {
           can=1;
          }
          mm++;
          find[s]=1;
          queue[mm].w=s;
          queue[mm].s=tt;
          if(i==0)
           queue[mm].d='r';
          else  if(i==1)
           queue[mm].d='l';
          else  if(i==2)
           queue[mm].d='d';
          else if(i==3)
           queue[mm].d='u';

 

         }
        }

        //对与反向的队列进行相同的操作
        x=b/3;
        y=b%3;
        xx=x+dir[i][0];
        yy=y+dir[i][1];
        if(xx>=0&&yy>=0&&xx<3&&yy<3&&can==0)
        {
         e=Fqueue[kk].w;
         g=e/t[b];
         h=e/t[xx*3+yy];
         g=g%10;
         h=h%10;
         e=e-g*t[b]-h*t[xx*3+yy];
         e=e+g*t[xx*3+yy]+h*t[b];
         if(find[e]==0)  //由于是相反的方向进行爬取则 记录相反的方向
         {
          find[e]=2;                                        /*错误的原因***/
          nn++;
          Fqueue[nn].w=e;
          Fqueue[nn].s=kk;
           if(i==0)
           Fqueue[nn].d='l';
          else  if(i==1)
           Fqueue[nn].d='r';
          else  if(i==2)
           Fqueue[nn].d='u';
          else if(i==3)
          Fqueue[nn].d='d';

         }


        }

       
     


    /***3**/}
          tt++;
    kk++;
     /*2*/}
                              //输出结果
  // cout<<"the final queue is:"<<queue[mm].w<<endl<<"ff"<<Fqueue[nn].w;//为了测试最后的结果是否是最终的目标
    i=0;j=mm;
    while(j>0)
    {
     ans[i++]=queue[j].d;
     j=queue[j].s;

    }
     for(int loop=i-1;loop>=0;loop--)
     cout<<ans[loop];
     i=0;
     j=0;
     while(Fqueue[j].w!=queue[mm].w)
      ++j;
     while(j>0)
     {
      ans[i++]=Fqueue[j].d;
      j=Fqueue[j].s;
     }
    
     for(int lo=0;lo<i;lo++)
      cout<<ans[lo];
     cout<<endl;

 /*1*/}

 else
  cout<<"My God !No answer\n";
 return 0;

 }

 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值