zoukankan      html  css  js  c++  java
  • 回溯法(挑战编程)

    回溯法,在以前也是会的,只不过没有系统的学习,只是从题目中接触了一些。

    今天,系统的学习了一下,颇有感触。

    对于回溯,书上的模版是这样的:

    bool finished = FLASE; /*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];
                backtrack(a, k, input);
                if(finished) return ;   //terminate early
            }
        }
    }

    对于各个函数的解释:

    is_a_solution(a, k, input):该函数测试向量a的前k个元素是否为一个完整解。最后一个参数input用来给这个函数传递一些其他信息。

    construct_candidates(a, k, input, c, ncandidates): 该函数根据a的前k-1个元素值,把第k个元素的所有候选值放到数组c中。候选值的数量为ncandidates。

    process_solution(a, k):当一个完整解呗构造出来后,对解进行处理。

    请注意递归是如何优美地实现回溯算法的。递归调用的每层都有自己的候选数组c,因此每个位置上那个尚未考虑的候选集不会相互影响。

    实例:

    1.构造所有子集:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int n;
    
    void backtrack(int a[], int k){
        int i;
        if(k == n){
            printf("{");
            for(i=1; i<=k; i++){
                if(a[i] == 1) printf(" %d", i);
            }
            printf(" }\n");
        }
        else{
            k = k+1;
            a[k] = 1;
            backtrack(a, k);
            a[k] = 0;
            backtrack(a, k);
        }
    }
    
    int main(){
        int a[30];
        scanf("%d", &n);
        backtrack(a, 0);;
    
        return 0;
    }

    2.构造所有排列:

    #include <stdio.h>
    
    #define MAXN 20
    
    void backtrack(int a[], int k, int n){
        int i, ncadidates, c[MAXN];
        unsigned char in_perm[MAXN];
    
        if(k == n){
            for(i=1; i<=n; i++) printf("%d ", a[i]);
            putchar('\n');
        }
        else{
             k = k+1;
             ncadidates = 0;
             for(i=1; i<=n; i++) in_perm[i] = 0;
             for(i=1; i<k; i++) in_perm[a[i]] = 1;
    
             for(i=1; i<=n; i++){
                 if(in_perm[i] == 0){
                     c[ncadidates] = i;
                     ncadidates++;
                 }
             }
    
             for(i=0; i<ncadidates; i++){
                 a[k] = c[i];
                 backtrack(a, k, n);
             }
        }
    }
    
    int main(){
        int n, a[MAXN];
        scanf("%d", &n);
        backtrack(a, 0, n);
    
        return 0;
    }

    3.八皇后问题:

    八皇后问题中每一行只能放置一个皇后,所以用一个一维数组就可以将排列位置存的下了。

    对于数组a[i],下标i表示i行,a[i]表示列。

    所以对于两个皇后,一定不在同一行,而:

    1.是否在同一列,检查a[i]是否等于a[j],相等则在同一行,否则不在。

    2.是否在一条斜线上,检查abs(i-j)是否等于abs(a[i]-a[j])。

    如此代码便很好写了。

    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAXN 15
    
    int solution_count;
    
    void construct_candidates(int a[], int k, int n, int c[], int *ncandidates){
        int i, j;
        unsigned char legal_move;
    
        *ncandidates = 0;
        for(i=1; i<=n; i++){
            legal_move = 1;
            for(j=1; j<k; j++){
                if(abs(k-j) == abs(i-a[j])) legal_move = 0; //对角线
                if(i == a[j]) legal_move = 0;//
                if(legal_move == 0) break;
            }
            if(legal_move == 1){
                c[*ncandidates] = i;
                (*ncandidates)++;
            }
        }
    }
    
    void backtrack(int a[], int k, int n){
        int c[MAXN];
        int ncandidates, i;
    
        if(k == n){
            solution_count++;
        }
        else{
            k++;
            construct_candidates(a, k, n, c, &ncandidates);
            for(i=0; i<ncandidates; i++){
                a[k] = c[i];
                backtrack(a, k, n);
            }
        }
    }
    
    int main(){
        int n, a[MAXN];
        solution_count = 0;
        scanf("%d", &n);
        backtrack(a, 0, n);
        printf("%d\n", solution_count);
    
        return 0;
    }
  • 相关阅读:
    C语言堆栈入门——堆和栈的区别(转)
    3--STM32 USB-三个HID-interface 复合(组合)设备的代码实现-基于固件库(原创)
    Spring 1 控制反转、依赖注入
    Java反射
    java多线程
    (六) 访问控制
    final关键字
    JSP(二):JSP九大内置对象、四个作用域对象
    JSP(一):JSP概要
    Servlet(九):web.xml文件和server.xml文件
  • 原文地址:https://www.cnblogs.com/tanhehe/p/3000984.html
Copyright © 2011-2022 走看看