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

    回溯算法的求解过程实质上是一个先序遍历一棵"状态树"的过程,只是这棵树不是遍历前预先建立的,而是隐含在遍历过程中。

    幂集

    即求一个集合的所有子集。比如对于集合A={1,2,3},则A的幂集为p(A)={{1,2,3},{1,2},{1,3},{1},{2,3},{2},{3},Φ}

    求幂集P(A)的元素的过程可看成是依次对集合A中元素进行“取”或“舍”的过程,并且可以用一棵状态树来表示。求幂集元素的过程即为先序遍历这棵状态树的过程。

     

    每个节点都是一个一维数组。

    这个问题中不存在剪枝,所有状态都是合法的。

    复制代码
    #include<vector>
    #include<iostream>
    #include<queue>
    using namespace std;
    
    template<typename Printable>
    void PowerSet(vector<Printable> &vec,queue<Printable> que){
        if(que.empty()){
            for(int i=0;i<vec.size();i++)
                cout<<vec[i]<<"  ";
            cout<<endl;
            return;
        }
        Printable ele=que.front();
        que.pop();
        vector<Printable> newvec(vec);
        vec.push_back(ele);
        PowerSet(newvec,que);
        PowerSet(vec,que);
    }
    
    int main(){
        string str="abcd";
        queue<char> que;
        vector<char> vec;
        for(int i=0;i<str.size();i++)
            que.push(str[i]);
        PowerSet(vec,que);
        return 0;
    }
    复制代码

    0-1背包问题

    给定n种物品和一背包。物品i的重量是wi>0,其价值为vi>0,背包的容量为c。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?

    跟上面的问题类似,对于每件物品都有选和不选两可能。

    利用回溯算法写还可以加入一些优化,进行剪枝,因为很多情况是没有意义的,例如当重量大于背包容量的时候,没有必要对剩下的物品再来决策了。或者将剩下的所有物品都选取其总价值也没有目前已经求得的方案的价值还大的话,也是可以剪枝的。

    下面编程求一个具体的背包问题。

    物品编号 大小 价值
    1 2 1
    2 3 4
    3 4 3
    4 5 6
    5 6 8

    最大价值:14
    放入包中的物体:4   5 

    走迷宫

    走迷宫可以用一个栈来解决。如果路径走得通就将其压入栈中,如果走不通就回退--对应出栈操作。最后栈里面存放的就是可靠路径。

    每个节点都是一个数。

    这里面仅仅使用一个“栈”很轻松地实现了“回溯”。

    N皇后

    在一个N×N的格子中放N个皇后,任意两个皇后都不能在同一行、同一列、同一斜线方向上。求所有可行的摆法。

    每个节点都是一个二维数组。实际上可以压缩一个一维数组以节省空间。

    复制代码
    #include<iostream>
    #include<vector>
    using namespace std;
    
    int numAnswer=0;
    void printTable(const vector<int> &);
    
    void queen(vector<int> vec,int rest){
        if(rest==0){
            cout<<"answer "<<++numAnswer<<endl;
            printTable(vec);
        }
        int num=vec.size()-rest+1;
        int i;
        for(i=0;i<vec.size();i++){
            if(vec[i]<0){
                bool b1=true,b2=true;
                for(int j=i-1;j>=0 && num-i+j>0;--j){
                    if(vec[j]==(num-i+j)){
                        b1=false;
                        break;
                    }
                }
                for(int j=i+1;j<vec.size() && num-j+i>0;++j){
                    if(vec[j]==(num-j+i)){
                        b2=false;
                        break;
                    }
                }
                if(b1 && b2){
                    vector<int> newvec(vec);
                    newvec[i]=num;
                    queen(newvec,rest-1);
                }
            }
        }
    }
    
    void printTable(const vector<int> &vec){
        int len=vec.size();
        for(int i=0;i<len;++i){
            for(int j=0;j<len;++j){
                if(vec[i]==j+1)
                    cout<<1<<" ";
                else
                    cout<<0<<" ";
            }
            cout<<endl;
        }
    }
    
    int main(){
        int len;
        cout<<"Input the number of queens"<<endl;
        cin>>len;
        vector<int> vec(len,-1);
        queen(vec,vec.size());
        return 0;
    }
    复制代码

    代码中利用递归实现树的向下增长,“剪树”是通过让函数return结束递归来完成的。

  • 相关阅读:
    stream流的统计demo
    ResourceBundle 读取文件demo
    spring boot 配置Filter过滤器的两种方式
    java工厂模式demo
    ThreadLocalDemo
    观察者模式Demo
    大数字的计算
    rabbitMQ消息丢失
    CF671E(线段树+单调栈)
    2020集训队作业板刷记录(三)
  • 原文地址:https://www.cnblogs.com/aukle/p/3223843.html
Copyright © 2011-2022 走看看