• 由八数码问题引入。对BFS有更深考虑


    12号到今天共研究八数码问题poj1077,首先用的是普通BFS,遇到很多问题,开始用一个二级指针作为结构成员,知道了二级指针与二维数值名的不同!http://write.blog.csdn.net/postedit!讲得不错。发现自己代码能力渣死!进入正题,用BFS过不了,先学习了八数码问题有解条件,并扩展到N数码有解问题。做到奇数偶数剪枝,过不了,太慢,于是学习了HASH判重,学习了康托展开(排列与数字的一一对应关系),效率大大增加!但是别人这样过了都,我是过不了啊!于是去学双广!没怎么看明白,,,很想放弃了!于是去学习了A*算法!(启发式搜索),46ms,BFS是最普通的A*,那么,我用优先队列优化,设置启发函数,把优先级高的先出队!本质已经破坏了BFS的分层搜索,倒是有点DFS了,我名之为bdfs!,有方向性!这样找一组解很容易!不用遍历所有!

    于是去切了骑士问题,先是8格的的,再是n格的,接下!

    #include<iostream> //优先(小的优先)队列BFS+hash判重+奇数偶数剪枝
    #include<queue>
    #include<string>
    #include<cstdio>
    #include<set>
    #include<cstring>
    using namespace std;
    string a;
    int f[4][2]={0,1,0,-1,1,0,-1,0};//方向
    bool state[362881];
    int fac[10]={1,1,2,6,24,120,720,5040,40320,362880};
    struct xy
    {
        string aa;    //当前状态
        int x;         //空格的坐标
        int y;
        int abs_to_end; //和目标数相同的方块数目!
        string s;      // 字符串,保存当前移动情况
        bool operator < (const xy & now) const //自定义离目标小的优先!
        {
            return now.abs_to_end>abs_to_end;
        }
    };
    int get_abs(string aa) //只要第一次获得,其他改变修改
    {
        int res=0;
       for(int i=1;i<=9;i++)
            {
                if(aa[i]!='9'&&aa[i]==('0'+i))res++;
            }
         return res;
    }
    
    bool has_solution()  //无解条件,奇偶剪枝!
    {
        int t[9];int count=0;
          for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                t[count++]=a[i*3+j]-'0';
        count=0;
       for(int i=0;i<9;i++)
         for(int j=i+1;j<9;j++)
            if(t[j]!=9&&t[i]!=9&&t[j]<t[i])count++;
       if(count%2==0)return 1;
       return 0;
    }
    string bfs(int ox,int oy)          //
    {
        priority_queue<xy>q;
        xy dian; dian.x=ox;dian.y=oy; //赋初值
        dian.s="";               //首地址的赋值,二维数组必先从一维建立。用的还是同一个!
    
        for(int i=0;i<3;i++)
           {
             for(int j=0;j<3;j++)
               {
                  dian.aa+=a[i*3+j];
               }
           }
         dian.abs_to_end=get_abs(dian.aa);
        q.push(dian);
        if(dian.aa=="123456789")return dian.s;
        while(!q.empty())
        {
             xy temp=q.top();
             q.pop();            //取队首拓展
            for(int i=0;i<4;i++)
              {                             // xy next=temp;这样只是完全赋值,指针指的是同一块地址!
                  xy next(temp);
                  int space=next.x*3+next.y;
                  next.x=next.x+f[i][0];           //四个方向拓展。
                  next.y=next.y+f[i][1];
                  if(next.x>=0&&next.x<3&&next.y>=0&&next.y<3)
                   {
                      if(i==0)
                       {
                           if(next.s.size()>0&&'l'==next.s[next.s.size()-1])continue;
                           next.s+="r";
                           if(next.aa[space+1]=='1'+space+1)next.abs_to_end--;
                          if(next.aa[space+1]=='1'+space)next.abs_to_end++;
                            next.aa[space]=next.aa[space+1];
                            next.aa[space+1]='9';
                       }
                       else if(i==1)
                       {
                           if(next.s.size()>0&&'r'==next.s[next.s.size()-1])continue;
                           next.s+="l";
                           if(next.aa[space-1]=='1'+space-1)next.abs_to_end--;
                           if(next.aa[space-1]=='1'+space)next.abs_to_end++;
                            next.aa[space]=next.aa[space-1];
                            next.aa[space-1]='9';
                       }
                        else if(i==2)
                       {
                           if(next.s.size()>0&&'u'==next.s[next.s.size()-1])continue;
                           next.s+="d";
                             if(next.aa[space+3]=='1'+space+3)next.abs_to_end--;
                             if(next.aa[space+3]=='1'+space)next.abs_to_end++;
                            next.aa[space]=next.aa[space+3];
                            next.aa[space+3]='9';
                       }
                        else if(i==3)
                       {
                           if(next.s.size()>0&&'d'==next.s[next.s.size()-1])continue;
                            next.s+="u";
                           if(next.aa[space-3]=='1'+space-3)next.abs_to_end--;
                           if(next.aa[space-3]=='1'+space)next.abs_to_end++;
                            next.aa[space]=next.aa[space-3];
                            next.aa[space-3]='9';
                       }
                    if(next.aa=="123456789")return next.s;
                    string ts=next.aa;                 //int hash(string ts)
                        int res=0;
                         for(int i=0;i<9;i++)
                           {
                               int count=0;
                              for(int j=i+1;j<9;j++)
                                    if(ts[j]<ts[i])count++;
                                  res+=count*fac[9-i-1];
                            }
                       if(state[res])continue;
                        state[res]=true;
                    q.push(next);
                   }
              }
        }
    }
    int main()
     {
        string ta;
        while(getline(cin,ta))
      {
         int ox,oy;
         a.clear();
         for(int i=0;i<ta.size();i++)
            {
                if(ta[i]=='x') a+='9';
                else if(ta[i]!=' ')a+=ta[i];
            }
        for(int i=0;i<a.size();i++)
         {
            if(a[i]=='9'){ox=i/3;oy=i%3;}
         }
        memset(state,0,sizeof(state));
        if(!has_solution())cout<<"unsolvable"<<endl;
        else
        {
            cout<<bfs(ox,oy)<<endl;
        }
      }
        return  0;
    }
    

  • 相关阅读:
    英雄
    Sublime text 2/3 中 Package Control 的安装与使用方法
    python安装
    flex与C# Socket通信
    ActionScript接收socket服务器发送来的数据
    什么是Socket,为什么要用Socket
    Response.End(); 用HttpContext.Current.ApplicationInstance.CompleteRequest 代替
    探索C#之6.0语法糖剖析
    行为树(Behavior Tree)实践(1)– 基本概念
    浅谈层次化的AI架构
  • 原文地址:https://www.cnblogs.com/yezekun/p/3925825.html
Copyright © 2020-2023  润新知