回溯法的基本框架

Backtracking 回溯算法的基本框架

维基百科上的回溯法定义:Backtracking is a general algorithm for finding all (or some) solutions to some computational problems, notably constraint satisfaction problems, that incrementally builds candidates to the solutions, and abandons each partial candidate c (“backtracks”) as soon as it determines that c cannot possibly be completed to a valid solution.

  • 回溯法通过枚举所有可能性来确保解答的正确
  • 回溯法不会访问一种状态超过一次,从而保证了解法的效率

Implementation 回溯法的算法框架

~~~C++
bool finished = FALSE; /* found all solutions yet? */

backtrack(int a[], int k, data input) {
int c[MAXCANDIDATES]; /* candidates for next position */
int ncandidates; /* next position candidate count */
int i; /* counter */

if (is_a_solution(a, k, input))
    process_solution(a, k, input);
else {
    k = k + 1;
    construct_candidates(a, k, input, c, &ncandidates);
    for (i = 0; i < ncandidates; i++) {
        a[k] = c[i];
        make_move(a, k, input);
        backtrack(a, k, input);
        unmake_move(a, k, input);
        if (finished) return;   /* terminate early */
    }
}

}

~~~

  • is_a_solution(a, k, input) 判断当前的部分解向量a[1…k]是否是一个符合条件的解
  • construct_candidates(a, k, input, c, ncandidates) 根据目前状态,构造这一步可能的选择,存入c[]数组,其长度存入ncandidates
  • process_solution(a, k, input) 对于符合条件的解进行处理,通常是输出、计数等
  • make_move(a, k, input) and unmake_move(a, k, input) 前者将所采用的选择更新到原数据结构中,后者把这一选择从原数据结构中删除

参考博客:@五岳的全面解析回溯法:算法框架与问题求解

回溯法的两个经典应用及算法框架

Constructing All Subsets 列出所有子集

主要实现以下三个函数

int is_a_solution(int a[], int k, int n) {
    return (k == n);
}

void construct_candidates(int a[], int k, int n, int c[], int *ncandidates) {
    c[0] = TRUE;
    c[1] = FALSE;
    *ncandidates = 2;
}

void process_solution(int a[], int k) {
    int i;              
    printf("{");
    for(i = 1; i <= k; i++)
        if(a[i] == TRUE)
            printf(" %d", i);
    printf(" }\n");
}

调用backtrack:

generate_subsets(int n) {
    int a[NMAX];
    backtrack(a, 0, n);
}

Constructing All Permutations 全排列

主要实现以下三个函数

construct_candidates(int a[], int k, int n, int c[], int *ncandidates) {
    int i;
    bool in_perm[NMAX];             /* Who is in the permutation? */
    for (i = 1; i <= NMAX; i++)
        in_perm[i] = FALSE;
    for (i = 0; i < k; i++)
        in_perm[a[i]] = TRUE;

    *ncandidates = 0;
    for (i = 1; i <= n; i++) {
        if (in_perm[i] == FALSE) {
            c[*ncandidates] = i;
            *ncandidates += 1;
        }
    }     
}

process_solution(int a[], int k) {
    int i;

    for (int i = 1; i <= k0; i++) 
        printf(" %d", a[i]);

    printf("\n");
}

is_a_solution(int a[], int k, int n) {
    return (k == n);
}

调用backtrack:

generate_permutations(int n) {
    int a[NMAX];

    backtrack(a, 0, n);
}

全排列的简化版回溯框架 (in Java)

public void backtrack(int[] num, int index) {
    if (index == num.length) {
        for (int j = 0; j < num.length; j++) 
            System.out.print(num[j]);

        System.out.println();
    }


    for (int i = index; i < num.length; i++) {
        swap(num, index, i);
        backtrack(num, index + 1);
        swap(num, index, i);
    }
}

public void swap(int[] A, int i, int j) {
    int temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值