• 回溯搜索(数独)


    这是我以前写的,现在转存在博客上

    玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3×3)内的数字均含1-9,不重复。

    给出格子的行和列我们可以确定格子在哪一个宫

    void cell(int x,int y)
    {
         return x / 3 * 3 + y / 3;
    }
    

    我们只需要枚举其余所有的点

    for(int map[][]=1;map[][]<10;map[][]++){
        if(check()){                              //每一层的check()是为了减少搜索次数的
            for(int map[][]=1;map[][]<10;map[][]++){  
                if(check()){
                    for(int map[][]=1;map[][]<10;map[][]++){
                        if(check()){                          
                            ....                  //可以用递归实现 
                            ....                  //
                        }
                    }
                }
            }
        }
    }
    

    这就是DFS,深度优先搜索

    递归写法模板

    //回溯法
    void dfs(答案,搜索层数,其他参数){
        if(层数==maxdeep){
            更新答案;
            return;
        }
        (剪枝)
        for(枚举下一层可能的状态){ 
            if(check()){
                  //更新全局变量表示状态的变量;
                  //dfs(答案+新状态增加的价值,层数+1,其他参数);     
                  //新状态必须是确定的,不能改变。
                  //还原全局变量表示状态的变量;
            }
        }
    }
    

    构造标记数组

    markrow[row][number];     //记录某一列是否存在某一个数字
    markcol[col][number];        //记录某一行是否存在某一个数字
    markbox[cell][number];      //记录某一宫是否存在某一个数字
    

    这里需要注意深度搜索的顺序会很大程度的影响到算法的效率

    代码

    #include<iostream>
    #include<algorithm>
    #include<utility>
    #include<cstdio>
    #include<cstring>
    
    using namespace std;
    
    int map[9][9]; pair<int, int> Next[81];
    int check = 0; // 已知的数的个数
    int k = 0;  //递归的深度
    
    int markrank[9][10];     //记录某一列是否存在某一个数字
    int markrow[9][10];      //记录某一列是否存在某一个数字
    int markcell[9][10];     //记录某一宫是否存在某一个数字
    
    int cell(int x, int y)
    {
          return x / 3 * 3 + y / 3;
    }
    
    // count函数用于记录(x,y)格子的还有几种可能情况
    int count(int x, int y)
    {
         int a[9] = { 0 }; int sum = 0;
         for (int i = 1; i <= 9; i++) {
             if (markrank[x][i] == 1 || markrow[y][i] == 1 || markcell[cell(x, y)][i] ==  1)
                    a[i - 1] = 1;
          }
         for (int i = 0; i < 9; i++) {
              if (a[i] == 1) sum++;
         }
         return sum;
    }
    
    //next()函数的作用是求出当前可能情况最少的格子
    pair<int, int> next() {
        pair<int, int> P2;
        int f = 0;
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                  if (map[i][j] == 0 && f == 1) {
                       if (count(P2.first, P2.second) < count(i, j))
                        {
                            P2.first = i; P2.second = j;
                        }
                   }
                   else if (map[i][j] == 0 && f == 0) {
                        P2.first = i; P2.second = j;
                        f++;
                   }
            }
        }
        return P2;
    }
    
    
    void dfs(int x, int y)
    {
        if (k == 81 - check) {
             for (int i = 0; i < 9; i++) {
                   for (int j = 0; j < 9; j++) {
                           cout << map[i][j] << " ";
                   }
                   cout << endl;
             }
         }
        else {
            for (int i = 1; i < 10; i++) {
                 if (markrank[x][i]==0 && markrow[y][i]==0 && markcell[cell(x,y)][i]==0){
                     map[x][y] = i;
                     markcell[cell(x, y)][i] = 1; markrank[x][i] = 1;  markrow[y][i] = 1;
                     k++;
                     if (Next[k].first == -1) {
                         pair<int, int> P = next();
                         Next[k] = P;
                     }
                     dfs(Next[k].first, Next[k].second);
                     k--;
                     markcell[cell(x, y)][i] = 0; markrank[x][i] = 0;  markrow[y][i] = 0;
                 }
            }
        }
    }
    int
    main()
    {
         memset(markrank, 0, sizeof(markrank));
          memset(markrow, 0, sizeof(markrow));
         memset(markcell, 0, sizeof(markcell));
          memset(Next, -1, sizeof(Next));
          for (int i = 0; i < 9; i++) {
              for (int j = 0; j < 9; j++) {
                      scanf("%d", &map[i][j]);
                      if (map[i][j] != 0) check++;
                      markcell[cell(i, j)][map[i][j]] = 1;
                      markrank[i][map[i][j]] = 1;
                      markrow[j][map[i][j]] = 1;
               }
          }
          pair<int, int> P = next();
          dfs(P.first, P.second);
          return 0;
    }
    

    解决数独的其他算法:dancing links 算法

    号称世界上最难的数独

    0 0 5 3 0 0 0 0 0
    8 0 0 0 0 0 0 2 0
    0 7 0 0 1 0 5 0 0
    4 0 0 0 0 5 3 0 0
    0 1 0 0 7 0 0 0 6
    0 0 3 2 0 0 0 8 0
    0 6 0 5 0 0 0 0 9
    0 0 4 0 0 0 0 3 0
    0 0 0 0 0 9 7 0 0
    
  • 相关阅读:
    如何获取喜欢的微信公众号封面图
    array_filter — 用回调函数过滤数组中的单元
    H5实现长按复制
    微信第三方平台 授权链接 报错
    Oracle 查询函数、存储过程、触发器、表、视图等
    Linux查看端口、及根据进程PID查看对应应用端口
    【Sed】sed n与正则
    【Android】android编译之source build/envsetup.sh简单用法
    一文搞定:SpringBoot、SLF4j、Log4j、Logback、Netty之间混乱关系(史上最全)
    数据库系列:高并发下的数据字段变更
  • 原文地址:https://www.cnblogs.com/axchml/p/13715278.html
Copyright © 2020-2023  润新知