回溯法(二)

回溯法(二)

  • 回溯法回顧
  • 揹包問題
  • 八皇后問題

回溯法總結

回溯法思路的簡單描述是:把問題的解空間轉化成了圖或者樹的結構表示,然後使用深度優先搜索策略進行遍歷,遍歷的過程中記錄和尋找所有可行解或者最優解,同時爲了加快搜索速度,可使用分支定界方法或約束方法進行剪枝(在當前節點(擴展節點)處,先生成其所有的兒子節點(分支),然後再從當前的活節點(當前節點的子節點)表中選擇下一個擴展節點。爲了有效地選擇下一個擴展節點,加速搜索的進程,在每一個活節點處,計算一個函數值(限界),並根據函數值,從當前活節點表中選擇一個最有利的節點作爲擴展節點,使搜索朝着解空間上有最優解的分支推進,以便儘快地找出一個最優解。分支限界法解決了大量離散最優化的問題。)

揹包問題

問題描述: 給定n種物品和一揹包。物品i的重量是wi,其價值爲pi,揹包的容量爲C。問應如何選擇裝入揹包的物品,使得裝入揹包中物品的總價值最大?
分析: 問題是n個物品中選擇部分物品,可知,如n = 3時,問題的解空間是子集樹,可將其轉化爲二叉樹。搜索二叉樹即可。其約束函數爲每次選擇一個物品時其揹包的容量是否超過C。
這裏寫圖片描述
代碼如下:

public class Main {

    private static int N = 3;
    private static int WW = 16;
    private int curWeight = 0;

    private int curValue = 0;
    private int bestValue = 0;

    private int[] x = {0,0,0};  //搜索標記
    private int[] best = {0,0,0};

    int[] w = {10,8,5};
    int[] v = {5,4,1};

    //遍歷搜索樹路徑
    public void traverse(int t){
        if(t > N-1){  //搜索到一個完整路徑
            if(curValue > bestValue){ //找到一個更優解
                bestValue = curValue;
                for(int i = 0; i < N; i++)best[i] = x[i];
            }
        }else{  //未找到一個完整的路徑
            for(int i =0; i <= 1; i++){
                x[t] = i;
                if(i ==0)traverse(t+1);  //不放入揹包
                else{  //放入揹包
                    if(curWeight+w[t] <= WW){
                        curWeight += w[t];
                        curValue += v[t];
                        traverse(t+1);
                        curWeight -= w[t];
                        curValue -= v[t];
                    }
                }
            }
        }
    }


    public static void main(String[] args) {
        Main main1 = new Main();
        main1.traverse(0);
        System.out.println("best:"+main1.bestValue);
        System.out.print("best seq:");
        for(int i = 0; i<N;i++){
            System.out.print(main1.best[i]);
        }
    }
}

八皇后問題

**問題描述:**n×n格的棋盤上放置彼此不受攻擊的n個皇后。按照國際象棋的規則,皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。則一共有多少种放法。
**分析:**n*n棋盤的每一層可以看作是一個選擇點,總共有n個選擇,即n叉樹。
這裏寫圖片描述

代碼如下

public class Main {

    private static int N = 8;  //棋盤大小
    private int[][] chess = new int[N][N]; //棋盤
    private int way = 0; //初始化

    /**
     * 判斷在棋盤
     * @param x
     * @param y
     * @return
     */
    public boolean isFeasible(int row,int col){
        if(row >=N  || row <0 || col >=N || col<0)return false;
        if(chess[row][col] != 0)return false;
        for(int i = 0; i < N; i++){  //行列不衝突
            if(chess[row][i] !=0 || chess[i][col] != 0)return false;
        }
        for(int i = 0; i<N;i++){ //斜線不衝突

            if((row-i)>=0 && (col-i)>=0)    //位置合法  
            {  
                if(chess[row-i][col-i] != 0)//此處已有皇后,衝突  
                    return false;  
            }  

            //左下角  
            if((row+i)<N && (col-i)>=0)  
            {  
                if(chess[row+i][col-i] != 0)  
                    return false;  
            }  

            //右上角  
            if((row-i)>=0 && (col+i)<N)  
            {  
                if(chess[row-i][col+i] != 0)  
                    return false;  
            }  

            //右下角  
            if((row+i)<N && (col+i)<N)  
            {  
                if(chess[row+i][col+i] != 0)  
                    return false;  
            }  
        }

        return true;
    }

    public void queen(int n){  //構成搜索樹
        if(n >=N){
            way++;
        }
        else{
            for(int i = 0; i<N;i++){ //搜索第n層樹的路徑
                if(isFeasible(n,i)){  //判斷第index行,第n列
                    chess[n][i] = 1;
                    queen(n+1);
                    chess[n][i] = 0;
                }
            }
        }
    }
    public static void main(String[] args) {
        Main main1 = new Main();
        main1.queen(0);
        System.out.println("總共有"+main1.way+"中放法");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章