Java算法學習:藍橋杯——七對數字(DFS✖回溯)

題目:

今有7對數字:兩個1,兩個2,兩個3,...兩個7,把它們排成一行。
要求,兩個1間有1個其它數字,兩個2間有2個其它數字,以此類推,兩個7之間有7個其它數字。如下就是一個符合要求的排列:

17126425374635

當然,如果把它倒過來,也是符合要求的。

請你找出另一種符合要求的排列法,並且這個排列法是以74開頭的。

注意:只填寫這個14位的整數,不能填寫任何多餘的內容,比如說明註釋等。

答案:74151643752362

(題目出處,藍橋杯七對數字)

解決思路:

排列相關,先想到DFS。套一個上一篇文章寫的dfs全排列模版。

DFS例舉所有的分支情況,回溯+剪枝處理當數字不能插入某個單元格的情況

這一題的退出條件因該是所有單元格都有數字,或者說已經處理到了最後一個空格。

遞歸的方式是當一對單元格插入完數據之後,進入下一個單元格進行1-7數字遍歷插入。

那我們就要對14個位置分別dfs。for循環創造1-7個多路遞歸。

代碼實現:

private static void dfs(int[] array,int pos){

        //跳出條件,當dfs到最後一個單元格之後,就會進入到dfs(array,13+1)
        if(pos==14){
            showArray(array);
            //一定要跳出整個函數否則下面語句會報數組溢出錯誤
            return;
        } 
          
        //遞歸調用情況1:包含了所有情況,如果當前單元格有數字,就跳過進入下一個
        if(array[pos]!=0){
            dfs(array,pos+1);
        }

        //遞歸調用情況2:for循環,在當前位置插入7個數字分別遞歸判斷,可行就插入,不可行就退回
        for (int i = 1; i <=7; i++) {
            //如果這個數字被用掉了
            if(visited[i-1]){
                continue;
            }
            //如果對應第二個同值數字超出數字範圍,跳出循環,之後的數字都不再例舉了。
            if(i+pos+1>13){
                break;
            }
            //檢測是否能插入數據(都爲0)
            if(array[pos+i+1]==0&&array[pos]==0){
                //修改
                array[pos] = array[i+pos+1] = i;
                visited[i-1]=true;
                //下一個數字

                dfs(array,pos+1);

                //走不通,恢復現場
                array[pos] = array[i+pos+1]=0;
                visited[i-1]=false;
            }/*if*/

        }/*for*/

    }/*dfs*/

以上就是核心dfs代碼,需要注意的點我都用註釋寫出,再次提出我遇到的坑就是:

  1. 想好遞歸跳出的條件,在這裏就是搜索到最後一個單元格(index==14)。
  2. 處理跳出條件的語句內,一定要有跳出整個函數的代碼,如果光輸出就完事兒的話,下面語句一定會報溢出錯誤。
  3. 遞歸下一個單元格的情況可能不止一種,在本題,就有兩種情況。一種是單元格佔用,一種是單元格完成插入。
  4. 最核心的回溯,好好體會一下。

全部代碼:

全部代碼如下,拷貝的時候注意包名和類名。

package 算法學習;

/**
 * Page Description:
 * User: ---
 * Date: 2019-03-15
 * Time: 下午 5:20
 * Function:
 */
public class _七對數字 {
    private static  int[] array = {7,4,0,0,0,0,4,0,7,0,0,0,0,0};
    private static boolean[] visited ={false,false,false,true,false,false,true};

    private static void showArray(int[] array){
        for (int i = 0; i <array.length ; i++) {
            System.out.printf("%d",array[i]);
        }
    }

    private static void dfs(int[] array,int pos){
        //跳出條件
        if(pos==14){
            showArray(array);
            return;
        }
        //已經佔用掉的數組位置,跳過進入下一個
        if(array[pos]!=0){
            dfs(array,pos+1);
        }
        //for循環,在當前位置插入7個數字分別遞歸判斷,可行就插入,不可行就退回
        for (int i = 1; i <=7; i++) {
            if(visited[i-1]){
                continue;
            }
            if(i+pos+1>13){
                break;
            }
            //檢測是否能插入數據(都爲0)
            if(array[pos+i+1]==0&&array[pos]==0){
                //修改
                array[pos] = array[i+pos+1] = i;
                visited[i-1]=true;
                //下一個數字

                dfs(array,pos+1);

                //走不通,恢復現場
                array[pos] = array[i+pos+1]=0;
                visited[i-1]=false;

            }/*if*/
        }/*for*/
    }/*dfs*/

    public static void main(String[] args) {
        dfs(array,2);
    }
}

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章