zoukankan      html  css  js  c++  java
  • 回溯法

    概念

    回溯法是把问题的解空间转化成了图或者树的结构表示,然后使用深度优先搜索策略进行遍历,遍历的过程中记录和寻找所有可行解或者最优解。

    首先从根节点出发搜索解空间树,当算法搜索至解空间树的某一节点时,先利用剪枝函数判断该节点是否可行(即能得到问题的解)。如果不可行,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。

    回溯法的基本行为是搜索,搜索过程使用剪枝函数来为了避免无效的搜索。剪枝函数包括两类:

      1.使用约束函数,剪去不满足约束条件的路径;

      2.使用限界函数,剪去不能得到最优解的路径。

    问题的关键在于如何定义问题的解空间,使之转化成树(即解空间树)。解空间树分为两种:子集树和排列树。

    当问题是要求满足某种性质(约束条件)的所有解或最优解时,往往使用回溯法。

    它有“通用解题法”之美誉。

    例子

    N皇后问题。解空间是一棵排列树。所以时间复杂度为O(n!)

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    int constraint(const int *arr, int row)
    {
        for (int i = 0; i < row; ++i)
        {
            if (arr[i] == arr[row] || arr[i]-arr[row] == i-row || arr[i]-arr[row] == row-i)
            {
                return 0;
            }
        }
    
        return 1;
    }
    
    
    void queen(int *arr, int len, int row, int *num)
    {
        if (row == len)
        {
            (*num)++;
        }
        else
        {
            for (int col = 0; col < len; ++col)
            {
                arr[row] = col;
                if (constraint(arr, row))
                {
                    queen(arr, len, row+1, num);
                }
            }
        }
    }
    
    
    int main(int argc, char const *argv[])
    {
        int n = -1;
        int num = 0;
    
        printf("input num of queen: ");
        scanf("%d", &n);
    
        // arr数组的索引代表“行数”,元素的值代表“列数”
        int *arr = (int*)malloc(n * sizeof(int));
        if (arr)
        {
            memset(arr, 0, n * sizeof(int));
            queen(arr, n, 0, &num);
            printf("%d
    ", num);
    
            free(arr);
        }
    
        
        return 0;
    }

     数独

    #include <stdio.h>
    #include <string.h>
    
    
    #define ARRSIZE 9
    
    
    int constraint(int (*arr)[ARRSIZE], int row, int col, int opt)
    {
        for (int i = 0; i < ARRSIZE; ++i)
        {
            if (opt == arr[i][col] || opt == arr[row][i])
            {
                return 0;
            }
        }
    
        int endrow = (row/3+1)*3;
        int endcol = (col/3+1)*3;
        for (int i = row/3*3; i < endrow; i++)
        {
            for (int j = col/3*3; j < endcol; ++j)
            {
                if (opt == arr[i][j])
                {
                    return 0;
                }
            }
        }
    
        return 1;
    }
    
    
    void sudoku(const int (*initArr)[ARRSIZE], int (*arr)[ARRSIZE], int row, int col)
    {
        if (row == ARRSIZE)
        {
            for (int i = 0; i < ARRSIZE; ++i)
            {
                for (int j = 0; j < ARRSIZE; ++j)
                {
                    printf("%d ", arr[i][j]);
                }
                printf("
    ");
            }
            printf("
    ");
        }
        else
        {
            if (initArr[row][col] != 0)
            {
                if (col < ARRSIZE-1)
                {
                    sudoku(initArr, arr, row, col+1);
                }
                else
                {
                    sudoku(initArr, arr, row+1, 0);
                }
            }
            else
            {
                for (int i = 1; i <= ARRSIZE; ++i)
                {
                    if (constraint(arr, row, col, i))
                    {
                        int tmp = arr[row][col];
                        arr[row][col] = i;
    
                        if (col < ARRSIZE-1)
                        {
                            sudoku(initArr, arr, row, col+1);
                        }
                        else
                        {
                            sudoku(initArr, arr, row+1, 0);
                        }
    
                        arr[row][col] = tmp;
                    }
                }
            }
        }
    }
    
    
    int main()
    {
        int arr[ARRSIZE][ARRSIZE] = {
            {8,0,0,0,0,0,0,0,0},
            {0,0,3,6,0,0,0,0,0},
            {0,7,0,0,9,0,2,0,0},
            {0,5,0,0,0,7,0,0,0},
            {0,0,0,0,4,5,7,0,0},
            {0,0,0,1,0,0,0,3,0},
            {0,0,1,0,0,0,0,6,8},
            {0,0,8,5,0,0,0,1,0},
            {0,9,0,0,0,0,4,0,0}
        };
        int initArr[ARRSIZE][ARRSIZE];
    
        memcpy(initArr, arr, ARRSIZE*ARRSIZE*sizeof(int));
    
        sudoku(initArr, arr, 0, 0);
    
        return 0;
    }
  • 相关阅读:
    升级windows 11小工具
    windows 10更新升级方法
    您需要了解的有关 Oracle 数据库修补的所有信息
    Step by Step Apply Rolling PSU Patch In Oracle Database 12c RAC Environment
    Upgrade Oracle Database Manually from 12.2.0.1 to 19c
    如何应用版本更新 12.2.0.1.210420(补丁 32507738 – 2021 年 4 月 RU)
    xtrabackup 安装、备份和恢复
    Centos_Lvm expand capacity without restarting CentOS
    Centos_Lvm_Create pv vg lv and mount
    通过全备+relaylog同步恢复被drop的库或表
  • 原文地址:https://www.cnblogs.com/zuofaqi/p/9926541.html
Copyright © 2011-2022 走看看