zoukankan      html  css  js  c++  java
  • 回溯之子集树和排列树

      再总结下回溯法,回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法。基本思想:在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。 而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。回溯法解题的时候常遇到两种类型的解空间树:子集树(选择问题)与排列树(排列问题)。当所给的问题是从n个元素的集合S中找出满足某种性质的子集时相应的空间就是子集树。当所给的问题是确定n个元素满足某种性质的排列时,相应的解空间树就是排列树。

    子集树(选择问题)的一个例子:

    #include <iostream>
    using std::cin;
    using std::cout;
    using std::endl;
    class Partsum {
    public:
        int S = 30;
        int num = 0;
        int x[7] = { 0 };
        int w[7] = { 0,5,10,12,13,15,18 };
        //回溯,sum为当前和,k为层数,r为剩余数的和
        void Backtrack(int sum, int k, int r) {
            if (sum + w[k] == S) {
                num++;
                cout << num << ":";
                cout << "S = ";
                for (int i = 1; i <= k; i++) {
                    if (x[i] == 1) {
                        cout << w[i] << "+";
                    }
                    else {
                        continue;
                    }
                }
                cout << w[k] << endl;
            }
            //到下一层sum小于S,则进入左子树
            if (sum + w[k] + w[k + 1] <= S) {
                x[k] = 1;
                Backtrack(sum + w[k], k + 1, r - w[k]);
            }
            //剪掉当前值,小于S则不可能是右子树了
            if (sum + r - w[k] >= S) {
                x[k] = 0;
                Backtrack(sum, k + 1, r - w[k]);
            }
        }
    };
    int main(int argc, char* argv[]) {
        Partsum p;
        p.Backtrack(0, 1, 73);
        return 0;
    }

    排列数(排列问题)的一个例子:

    #include <iostream>
    using std::cin;
    using std::cout;
    using std::endl;
    class Arranage {
    public:
        float A[4] = { 0,1,2 };
        void arrage(int k, int m) {
            int i, temp;
            if (k == m) {
                for (i = 0; i <= m; i++) {
                    cout << A[i] << " ";
                }
                cout << endl;
            }
            else {
                for (i = k; i <= m; i++) {
                    swap(A[k], A[i]);
                    arrage(k + 1, m);
                    swap(A[i], A[k]);
                }
            }
        }
        template<class Type>
        void swap(Type &x, Type &y) {
            Type temp;
            temp = x;
            x = y;
            y = temp;
        }
    };
    int main(int argc, char* argv[]) {
        Arranage arr;
        arr.arrage(0, 2);
        return 0;
    }

     

  • 相关阅读:
    BZOJ3129/洛谷P3301方程(SDOI2013)容斥原理+扩展Lucas定理
    Dilworth定理
    字符串
    hash
    李超线段树(segment[HEOI2013]-洛谷T4097)
    连通数[JSOI2010]-洛谷T4306
    主席树
    splay
    树链剖分
    受欢迎的奶牛-洛谷2341
  • 原文地址:https://www.cnblogs.com/SHNLQS-1273196803/p/11061218.html
Copyright © 2011-2022 走看看