• vijos 1360 八数码问题


    背景

    Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.

    描述

    在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

    格式

    输入格式

    输入初试状态,一行九个数字,空格用0表示

    输出格式

    只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

    样例1

    样例输入1

    283104765

    样例输出1

    4

      这题直接广搜是可以的,不过非常地耗费内存和时间,所以这里用到了A*算法

    股价函数是以它和目标节点的差作股价,不过单用股价函数是不可以的(全W的教训)

    还要有现在所走的步数,把两者相加,得到优先级,优先级越低的越先搜索

    priority = h(x) + step;

       如何说明这个的正确性呢?假设有有一个节点x,h(x) = 2,如果它不能尽快地达到目标状态,以至于优先级超过排在第二的节点y,那么y就会被取出队列进行更新。要使股价函数h(x)的值要减少1(当h(x)=2时是特例),至少需要移动一步,这样就能够保证第一次搜到目标节点一定步数是最少的。如果还不明白,就这么再说一下个人的理解,(h[x]+step)是按照最优的情况移动一次h(x)就减少了1的步数加1进行预算,如果最优的情况下x都不比y优,那么就应当先搜索y。       

    Code:

      1 /**
      2  * Vijos.org
      3  * Problem#1360
      4  * Accepted
      5  * Time:76ms
      6  * Memory:996k
      7  **/
      8 #include<iostream>
      9 #include<queue>
     10 #include<set>
     11 using namespace std;
     12 typedef bool boolean;
     13 typedef class MyData{
     14     public:
     15         char datas[3][3];
     16         void in(){
     17             for(int i=0;i<=2;i++){
     18                 for(int j=0;j<=2;j++){
     19                     cin>>datas[i][j];
     20                 }
     21             }
     22         }
     23         MyData(){}
     24         MyData(string str){
     25             for(int i=0;i<=8;i++){
     26                 this->datas[i/3][i%3] = str[i];
     27             }
     28         }
     29         boolean equals(MyData another){
     30             for(int i=0;i<=2;i++){
     31                 for(int j=0;j<=2;j++){
     32                     if(this->datas[i][j]!=another.datas[i][j]) return false;
     33                 }
     34             }
     35             return true;
     36         }
     37         boolean operator <(MyData another) const{
     38             
     39             for(int i=0;i<=2;i++){
     40                 for(int j=0;j<=2;j++){
     41                     if(this->datas[i][j]!=another.datas[i][j]) return this->datas[i][j]<another.datas[i][j];
     42                 }
     43             }
     44             return false;
     45         }
     46 }MyData;
     47 typedef class Node{
     48     public:
     49         int pro;
     50         int step;
     51         MyData d;
     52         int x;
     53         int y;
     54         Node():pro(9),step(0){}
     55         Node(int pro,int step,MyData d):pro(pro),step(step),d(d){}
     56         boolean operator <(Node another) const{
     57             return this->pro>another.pro;
     58         }
     59 }Node;
     60 int fstep = -1;
     61 priority_queue<Node> que;
     62 set<MyData> s;
     63 int m[2][4]={{1,0,-1,0},{0,1,0,-1}};
     64 MyData aim("123804765");
     65 int h(Node node){
     66     int result = 0;
     67     for(int i=0;i<=2;i++){
     68         for(int j=0;j<=2;j++){
     69             if(node.d.datas[i][j]!=aim.datas[i][j]) result++;
     70         }
     71     }
     72     return result;
     73 }
     74 void swap(Node* node,int x,int y,int x1,int y1){
     75     char a=node->d.datas[x][y];
     76     node->d.datas[x][y]=node->d.datas[x1][y1];
     77     node->d.datas[x1][y1]=a;
     78 }
     79 void find(Node start){
     80     start.step = 0;
     81     start.pro=h(start);
     82     for(int a=0;a<=2;a++){
     83         for(int b=0;b<=2;b++){
     84             if(start.d.datas[a][b]=='0'){
     85                 start.x=a;
     86                 start.y=b;
     87                 break;
     88             }
     89         }
     90     }
     91     s.insert(start.d);
     92     que.push(start);
     93     while(!que.empty()){
     94         Node e = que.top();
     95         que.pop();
     96         if(fstep != -1&&e.step >= fstep) continue;
     97         if(e.d.equals(aim)) fstep = e.step;
     98         for(int i=0;i<=3;i++){
     99             Node eu = e;
    100             int x=eu.x,y=eu.y;
    101             eu.x += m[0][i];
    102             eu.y += m[1][i];
    103             if(eu.x>=0&&eu.x<=2&&eu.y>=0&&eu.y<=2){
    104                 swap(&eu,x,y,eu.x,eu.y);
    105                 eu.pro = h(eu) + eu.step + 1;
    106                 eu.step++;
    107                 if(!s.count(eu.d)){
    108                     s.insert(eu.d);
    109                     que.push(eu);
    110                 }
    111             }
    112         }
    113     }
    114 }
    115 int main(){
    116     MyData d;
    117     d.in();
    118     find(Node(0,0,d));
    119     cout<<fstep;
    120     return 0;
    121 }
  • 相关阅读:
    SQLServer字符串与数字拼接
    今天踩了一个低级坑
    DataTable Linq Group Count where写法
    红米note7几个问题处理
    Svn CleanUp failed解决方案
    VisualSVN 新版本终于支持一个解决方案下多workcopy了,并解决了上个版本一个重要BUG
    UML类图
    EXT.net 1.x TreePanel的一个坑
    AntDesign vue学习笔记(九)自定义文件上传
    C# Convert.ChangeType()
  • 原文地址:https://www.cnblogs.com/yyf0309/p/5661648.html
Copyright © 2020-2023  润新知