由全排列問題簡談DFS

先貼簡單的全排列問題地址 : https://www.luogu.com.cn/problem/P1706 本題說的是n的全排列

本題是最典型的最入門的DFS問題,可採用回溯法。一眼看覺得很簡單,第一次動手寫發現許多細節問題,也理解了很長時間,所以在此分享一下個人的理解(PS:很多大佬發的題解確實沒有仔細地說明緣由和代碼的層次問題,我說一下吧)

首先要知道DFS的原理,如果不理解的話一定要多畫圖,每畫一筆都要想想爲什麼這麼畫,下一步怎麼得出來的。不多說,直接上代碼後面分析。

import java.util.Scanner;

public class 全排列_標記法 {
	static Scanner sc = new Scanner(System.in);
	static int n = sc.nextInt();
	static int result[] = new int[n+1];
	static int vis[]  = new int[n+1];
	public static void main(String[] args) {
		DFS(1);//對應下文問題1
	}

	private static void DFS(int step) {
		if(step >= n+1) {//對應問題3
			print();
			return;
		}
		for(int j = 1 ; j <= n ; j++) {//對應問題3
			if(vis[j] == 0) {
				vis[j] = 1;//標記數組,見問題2
				result[step] = j;
				DFS(step+1);
				vis[j] = 0;//回溯,見問題2
			}
		}
	}

	private static void print() {
		for(int i = 1; i <= n; i++) {//對應問題3
			System.out.printf("%5d",result[i]);
		}
		System.out.println();
	}
	
}

對於代碼中的一些問題這裏說一下。

1.爲什麼dfs參數從1開始,1是什麼意思?

答:我們將題目當成裝箱子問題,第一步(step)是選擇第一個箱子,然後是第二個箱子,直到把所有的箱子選完並裝完數字。要注意的是,每選完一個箱子,就立即選擇一個數字裝入,再進入dfs循環,選擇下一個箱子。

2.這裏的vis[]數組怎麼理解?

答:vis[]數組的vis -> visit訪問,指的是判斷訪問數組,其數組默認值爲0,所以當vis[i]==0時,當作此元素未被訪問過(也就是未被標記過),而vis[i]==1時,指此元素已被訪問標記過。

3.回溯不知如何層次在哪裏,vis[i] = 0有何作用?

答:這個問題,你應該自己去仔細畫一遍dfs的圖,看看其原理,是什麼時候往回退的,一步步往回退的過程就是回溯,過程中將已經訪問過的元素重新賦值爲0。因爲你賦值爲0的一個重要作用,就是在你觸底,不能在繼續訪問新元素的時候,要往回退,往回退的過程中還要有另一條路會用到此元素,有種重點理解的地方,這個數字只存在與一個數組中,你訪問數字,即爲訪問數組的元素,而且是隻有一個數組,所以要一步步的回溯。例如:從1-4的過程中,當你選擇step1:1  ->  step2 : 2 ->  step3 : 3 -> step4 : 4 。此時1234這4個數字都被訪問過,vis[i]都爲1,如果你要換一種排列,他們都不在訪問範圍內,所以第一步回溯,將step4中的4 vis[i]重新置爲0,然後發現除了4沒有其他數字選擇,那麼再次回溯,將step3的數字的也置爲0(不是數字置爲0,而是vis[]置爲0),此時就有了選擇,除了3以外,4也沒被訪問過,所以第二種方案,爲step3爲4,然後繼續dfs,step4爲3.(最後的結果 爲 :1243)。

4.step==n+1爲什麼不能是step==n,循環爲何要從int i = 1開始?

答:前者,step==n是可行的,他與dfs函數一開始的位置有關,但是輸出可能不盡人意,dfs從1開始,意味着選擇了第一個箱子,所以對應的觸底反彈的底就是step==n+1。如果你願意寫從第0個箱子開始,也是可以的。

後者問題的答案,在DFS函數中 int i = 1,指的是數字i從1開始,就是題目要求的1-n之間的數字,不能從0開始,這樣違反題目規則。在print函數中,其實與前者問題掛鉤,我們捨棄了result[0]這個位置,因爲主觀上我們都是從第一個箱子開始,當然你改成int i = 0也可以,但是的dfs參數和step==n+1也需要改。這三者是互相聯繫的。

整體理解:切記dfs的順序,step到底時不代表全部結束,因爲此程序跑完會有很多次step==n或者step==n+1的情況。

這是數組標記法,還有一種交換法dfs的方法,我整理後再發!

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