zoukankan      html  css  js  c++  java
  • 遞歸回溯解決8皇后問題

    今天學習了經典的8皇后問題,强化了對遞歸調用的理解,之前自己寫遞歸老是把出口條件理解錯,導致邏輯錯誤,時常抛棧溢出的錯誤.

    其實簡單來説遞歸調用,在調用之前,一定要想明白,遞歸出口在哪裏,在調用遞歸的時候,怎麽能讓遞歸的代碼不斷向出口方向靠近,

    最終能找到遞歸的出口.這個問題想明白了,遞歸調用也就成功了一半了.

    之前在調用遞歸時還發現,遞歸説到底是通過棧進行計算,如果在遞歸裏調用了堆裏的東西,一定不能是new出來的對象.

    而且遞歸調用時要盡量把調用遞歸用到的資源放到外面,減少遞歸調用的資源.

    舉個簡單例子來説,寫一個輸出重複語句的遞歸方法,代碼本身沒問題,但是如果調用方法次數過多,仍然會抛出棧溢出的錯誤.

    用代碼測試過,一個簡單的輸出語句,在我電腦上,用String直接調用遞歸方法,一旦超過6200次就可能抛異常,

    用StringBuilder調用遞歸方法,一旦超過12000次也可能抛異常

    今天老師講的遞歸實現8皇后的方法確實很經典.占用資源也不多,但老師說,實際上這樣的算法大概得調用14000多次遞歸方法

    由此可見,其實遞歸方法代碼占用的資源和代碼本身的複雜程度關係並不大,關鍵還是看代碼怎麽設計的,

    怎麽能夠在調用時還能保證不占用過多的計算機資源.

    以上就是我本人對於遞歸的一些粗淺的理解.

    下面放上我重寫過的遞歸解決8皇后問題的代碼.

     1 package com.recursion;
     2 
     3 /*
     4  * 遞歸回溯解決8皇后問題
     5  * 需求,根據象棋的規則,在棋盤上放置8個皇后,每個皇后的下一步棋不能吃子
     6  * 棋盤上放置到第8個皇后時,8個皇后的位置作爲一個正解,算出總共有多少正解
     7  * 
     8  * 遞歸回溯的思路
     9  * 將第一個皇后放在第一行第一列,放第二個皇后,看下一步棋是否能吃子,
    10  * 不能吃子則放第三個皇后,放置下一個子時,位置可能回溯,發生變化
    11  * 放到第8個皇后時開始回溯求解
    12  * 得到一個正確解就會退回一個棧,會把棧裏所有的可能性都嘗試一遍,
    13  * 退回上一個棧,再次求解,一直回溯到第一個皇后
    14  * 
    15  */
    16 public class EightQueen {
    17     //1,共有8個皇后
    18     int max = 8;
    19     //1,定義存放解法的數組
    20     int[] array = new int[max];
    21     //5,定義解法的變量
    22     static int count = 0;
    23     public static void main(String[] args) {
    24         // TODO Auto-generated method stub
    25         //1,用一維數組表示棋盤,索引表示行坐標,數值表示列坐標
    26         //定義一個將皇后放的位置輸出的方法
    27         //4,調用遞歸方法測試
    28         EightQueen queen8 = new EightQueen();
    29         queen8.check(0);
    30         //5,統計共有多少種解法
    31         System.out.printf("一共有%d種解法",count);
    32     }
    33     
    34     //3,定義放置皇后的方法,每一次進入check都會循環遞歸,知道得出正解
    35     private void check(int n) {
    36         //n為8時,方法為正解,遞歸出口
    37         if (n == max) {
    38             print();
    39             return;
    40         }
    41         //放置皇后,判斷是否衝突
    42         for (int i = 0; i < max; i++) {
    43             //把皇后n放到第一列
    44             array[n] = i;
    45             if (judge(n)) {
    46                 //如果不冲突,開始放第n+1個皇后,開始遞歸
    47                 check(n + 1);
    48             }
    49             //如果衝突,遞歸繼續循環,去下一行
    50         }
    51     }
    52     
    53     //2,定義查看放置第n個皇后是否滿足放置規則的方法
    54     /**
    55      * 
    56      * @param n 表示第n個皇后
    57      * @return
    58      */
    59     private boolean judge(int n) {
    60         for (int i = 0; i < n; i++) {
    61             //判斷第n個皇后和第n-1個皇后是否在同一列,n本身在自增運算,不需要判斷行
    62             //判斷第n個皇后和第i個皇后是否在同一斜綫
    63             if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) {
    64                 return false;
    65             } 
    66         }
    67         return true;
    68     }
    69     
    70     //1,定義打印輸出的方法
    71     private void print() {
    72         count++;
    73         for (int i = 0; i < array.length; i++) {
    74             System.out.print(array[i] + " ");
    75         }
    76         System.out.println();
    77     }
    78 
    79 }

    代碼不多,卻解決了一個比較複雜的經典計算問題.

  • 相关阅读:
    hdu6229 Wandering Robots 2017沈阳区域赛M题 思维加map
    hdu6223 Infinite Fraction Path 2017沈阳区域赛G题 bfs加剪枝(好题)
    hdu6438 Buy and Resell 买卖物品 ccpc网络赛 贪心
    hdu6441 Find Integer 求勾股数 费马大定理
    bzoj 1176 Mokia
    luogu 3415 祭坛
    bzoj 1010 玩具装箱
    bzoj 3312 No Change
    luogu 3383【模板】线性筛素数
    bzoj 1067 降雨量
  • 原文地址:https://www.cnblogs.com/zzzzzpaul/p/11588020.html
Copyright © 2011-2022 走看看