• BFS-八数码问题与状态图搜索


      在一个3*3的棋盘上放置编号为1~8的八个方块,每个占一格,另外还有一个空格。与空格相邻的数字方块可以移动到空格里。任务1:指定的初始棋局和目标棋局,计算出最少的移动步数;任务2:数出数码的移动序列。

      把空格看成0,一共有九个数字。

      输入样例:

      1 2 3 0 8 4 7 6 5 

      1 0 3 8 2 3 7 6 5 

      输出样例:

      2

      1.把一个棋局看成一个状态图,总共有9!= 362880个状态。从初始棋局开始,每次移动转到下一个状态,达到目标棋局后停止。

      2.康托展开

        康托展开是一种特殊的哈希函数。其功能是在输入一个排列,计算出它在在全排列中从小到大排序的位次。

        eg:判断 2143是{1,2,3,4}的全排列中的位次。

          (1)首位小于2的所有排列。比2小的只有1,后面三个数的排列有3*2*1=3!个,写成1*3!=6

          (2)首位为2,第二位小于1的所有排列。无,写成0*2!=0

          (3)前两位为21,第三位小于4的所有排列。只有3一个数,写成1*1!=1

          (3)前三位为214,第四位小于3的所有排列。无,写成0*0!=0

          求和:1*3!+0*2!+1*1!+0*0!=7

        所以位次的计算公式为X = a[n]*(n-1)! +a[n-1]*(n-2)! + … + a[1]*0!

      

     1 #include<bits/stdc++.h>
     2 #include<queue>
     3 using namespace std;
     4 
     5 const int len = 362880; //状态共9! = 362880种
     6 int visited[len] = {0};//标记已有状态用来去重 
     7 int start[9];//起始状态 
     8 int goal[9];//目标状态 
     9 int factory[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362800};//0到9的阶乘 
    10 int dir[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
    11 
    12 struct node{
    13     int state[9];//棋局状态按一维存放下来 
    14     int dis;//记录从起始状态移动到当前状态的步数 
    15 };
    16  
    17 bool cantor(int str[], int n){
    18     int result = 0;
    19     for(int i=0; i<n; i++){
    20         int cnt = 0;
    21         for(int j=i+1; j<n; j++){
    22             if(str[i] > str[j])
    23                 cnt ++;
    24         }
    25         result += cnt*factory[n-i-1];
    26     }
    27     if(!visited[result]){
    28         visited[result] = 1;
    29         return 1;
    30     }
    31     return 0;
    32 }
    33 
    34 int BFS(){
    35     node head, next;
    36     memcpy(head.state, start, sizeof(head.state));//复制起始状态并插入队列 
    37     head.dis = 0; 
    38     cantor(head.state, 9);
    39     queue<node>q;
    40     q.push(head);
    41     
    42     while(!q.empty()){
    43         head = q.front();
    44         q.pop();
    45         int z;
    46         for(z=0; z<9; z++)
    47             if(head.state[z] == 0)//找到0 
    48                 break;
    49         int x = z % 3;//将0的一维位置转化为二维的横纵坐标 
    50         int y = z / 3;
    51         for(int i=0; i<9; i++){
    52             int newx = x + dir[i][0];
    53             int newy = y + dir[i][1];
    54             int newz = newx + 3*newy;//将0移动后重新转化为一维坐标 
    55             if(newx>=0 && newx<3 && newy>=0 && newy<3){//避免越界 
    56                 memcpy(&next, &head, sizeof(struct node));
    57                 swap(next.state[z], next.state[newz]);//复制原先状态后,改变0的位置 
    58                 next.dis ++;
    59                 if(memcmp(next.state, goal, sizeof(next.state)) == 0)
    60                     return next.dis;
    61                 if(cantor(next.state, 9))//查重 
    62                     q.push(next);
    63             } 
    64         }
    65     }
    66     return -1;
    67 }
    68 
    69 int main(){
    70     for(int i=0; i<9; i++)
    71         scanf("%d", start+i);
    72     for(int i=0; i<9; i++)
    73         scanf("%d", goal+i);
    74     
    75     int num = BFS();
    76     if(num != -1)
    77         printf("%d
    ",num);
    78     else
    79         printf("Impossible
    "); 
    80 }

      (1)用于存放状态图的以及步数的结构体

      (2)用于移动的数组

      (3)用于去重的标记数组

      (4)提前算好阶乘存放于数组中

      (5)康拓函数判重

      (6)BFS函数:queue<node>q;node head, next;

      (7)状态图中某数字方块的一维坐标和二维坐标的相互转化

      (8)检查坐标是否合法   

    八数码问题多种解法:https://www.cnblogs.com/zufezzt/p/5659276.html

  • 相关阅读:
    Redis操作命令大全
    Redis实用监控工具一览
    Redis缓存雪崩、缓存穿透、缓存击穿、缓存降级、缓存预热、缓存更新
    Redis GEO地理位置信息,查看附近的人
    详解redis持久化
    详解Supervisor进程守护监控
    详解Redis Cluster集群
    arduino使用rfid
    树莓派控制WS2812
    Arduino读取温湿度dh11+烟雾气体MQ2+彩灯ws2812
  • 原文地址:https://www.cnblogs.com/0424lrn/p/12229971.html
Copyright © 2020-2023  润新知