역 추적 : 이전 시퀀스 번호가 유사한 알고리즘 탐색 검색 (왼쪽, 오른쪽)의

사실, 의사 결정 트리 탐색을 문제를 해결하기 위해 역 추적 . 당신은 세 가지 질문에 대해 생각해야합니다 :

1, 경로 :이며, 선택을했다.

목록을 선택하십시오 :, 당신은 현재의 선택을 할 수 있습니다.

3, 마지막 조건 :이며, 조건을 선택하지, 의사 결정 트리의 하단에 도달.

당신이이 세 단어의 설명을 이해하지 못한다면 우리가 당신은이 단어가 무슨 뜻인지 이제 첫번째 킵 이해 "전체 배열"과 "도움말 알고리즘을 역 추적의 N 여왕 '이 고전적인 문제를 사용, 그것은 중요하지 않아 인상.

코드 측, 알고리즘 프레임 워크를 역 추적 :

result = []
def backtrack(路径, 选择列表):
    if 满足结束条件:
        result.add(路径)
        return

    for 选择 in 选择列表:
        做选择
        backtrack(路径, 选择列表)
        撤销选择

그것의 핵심은 "메이크업의 선택", 재귀 호출 후 "선택 해제"로 재귀 호출하기 전에, 재귀 루프 내부입니다 특히 간단합니다.

선택과 선택 해제,이 프레임 워크의 기본 원칙이 무엇이다는 무엇입니까? 여기에서 우리는이 문제를 비밀에 대한 자세한 문의를 통해 해결 될 전에 "전체 배열이"의아해있다!

첫째, 전체 배열 문제

우리는 포트폴리오를 정렬 고등학교 수학 문제에서 그것을했다, 우리는 또한 알고 n비 반복의 숫자! n 번째의 총의 전체 배열.

추신 : 단순하고 명확하게하기 위해, 모든 문제는 우리는이 논의가 중복되는 번호가 포함되어 있지 않습니다 배열 .

우리는 어떻게 철저한으로 가득 배열을했다? 세 개의 숫자에 대한하자의 말 [1,2,3], 당신은 확실히 불규칙하지 철저한 혼란이 같은 보통 일 것입니다 :

먼저 고정 제 비트, 다음 제 3 개만 인 후 제 2 일 수 있고, 1 일 후 3 번째 위치에 설정할 수 3 위은 2 것까지, 다음 만 변화 할 수 ...... 처음 두 후에는 완전한 2가되고,

언제 까지나 사실에 트리 탐색, 루트에서 경로에 디지털 기록, 전체 배열의 모든있다. 우리는 "의사 결정 트리」라는 트리 역 추적 알고리즘을 얻고 자하는 .

지금, 당신은이 핵심 프레임 워크 되돌아 알고리즘을 이해합니까?

for 选择 in 选择列表:
    # 做选择
    将该选择从选择列表移除
    路径.add(选择)
    backtrack(路径, 选择列表)
    # 撤销选择
    路径.remove(选择)
    将该选择再加入选择列表

 

언제 까지나 우리가 재귀 옵션 뒤에 재귀, 탈퇴하기 전에 선택을로 , 당신은 바로 경로와리스트의 각 노드를 선택할 수 있습니다.

다음으로, 전체 배열은 직접 코드를 참조하십시오

List<List<Integer>> res = new LinkedList<>();

/* 主函数,输入一组不重复的数字,返回它们的全排列 */
List<List<Integer>> permute(int[] nums) {
    // 记录「路径」
    LinkedList<Integer> track = new LinkedList<>();
    backtrack(nums, track);
    return res;
}

// 路径:记录在 track 中
// 选择列表:nums 中不存在于 track 的那些元素
// 结束条件:nums 中的元素全都在 track 中出现
void backtrack(int[] nums, LinkedList<Integer> track) {
    // 触发结束条件
    if (track.size() == nums.length) {
        res.add(new LinkedList(track));
        return;
    }

    for (int i = 0; i < nums.length; i++) {
        // 排除不合法的选择
        if (track.contains(nums[i]))
            continue;
        // 做选择
        track.add(nums[i]);
        // 进入下一层决策树
        backtrack(nums, track);
        // 取消选择
        track.removeLast();
    }
}

두, N은 문제를 여왕

당신에게 N × N 체스 판을 제공하는 당신이 N이 서로를 공격 할 수 있도록 퀸즈 배치하자 :이 설명하는 매우 고전적인, 간단합니다.

PS는 여왕이 오른쪽 오른쪽 아래 왼쪽 위의 네 방향 좌하 임의 단위에서 동일한 행에 동일한 열을 공격 할 수있다.

거의 모든 치환 문제와 문제의 본질은, 트리의 각 층은 상기 기판의 각 행을 나타내고, 각 노드는 퀸의 행 중 어느 하나를 배치위한 선택이 이루어질 수있다.

프레임에 직접 적용 :

vector<vector<string>> res;

/* 输入棋盘边长 n,返回所有合法的放置 */
vector<vector<string>> solveNQueens(int n) {
    // '.' 表示空,'Q' 表示皇后,初始化空棋盘。
    vector<string> board(n, string(n, '.'));
    backtrack(board, 0);
    return res;
}

// 路径:board 中小于 row 的那些行都已经成功放置了皇后
// 选择列表:第 row 行的所有列都是放置皇后的选择
// 结束条件:row 超过 board 的最后一行
void backtrack(vector<string>& board, int row) {
    // 触发结束条件
    if (row == board.size()) {
        res.push_back(board);
        return;
    }

    int n = board[row].size();
    for (int col = 0; col < n; col++) {
        // 排除不合法选择
        if (!isValid(board, row, col)) 
            continue;
        // 做选择
        board[row][col] = 'Q';
        // 进入下一行决策
        backtrack(board, row + 1);
        // 撤销选择
        board[row][col] = '.';
    }
}

메인 코드의이 부분은 사실, 전체 배열과 유사의 문제 isValid 달성하기 기능은 매우 간단합니다 :



/* 是否可以在 board[row][col] 放置皇后? */
bool isValid(vector<string>& board, int row, int col) {
    int n = board.size();
    // 检查列是否有皇后互相冲突
    for (int i = 0; i < n; i++) {
        if (board[i][col] == 'Q')
            return false;
    }
    // 检查右上方是否有皇后互相冲突
    for (int i = row - 1, j = col + 1; 
            i >= 0 && j < n; i--, j++) {
        if (board[i][j] == 'Q')
            return false;
    }
    // 检查左上方是否有皇后互相冲突
    for (int i = row - 1, j = col - 1;
            i >= 0 && j >= 0; i--, j--) {
        if (board[i][j] == 'Q')
            return false;
    }
    return true;
}

 

게시 된 159 개 원래 기사 · 원 찬양 75 · 전망 190 000 +

추천

출처blog.csdn.net/xuehuagongzi000/article/details/104299224