靜態路由綜合實驗
阿新 • • 發佈:2021-10-25
今天寫了這道題才明白遞迴搜尋樹的含義
從 1∼n 這 n 個整數中隨機選出 m 個,輸出所有可能的選擇方案。 輸入格式 兩個整數 n,m ,在同一行用空格隔開。 輸出格式 按照從小到大的順序輸出所有方案,每行 1 個。 首先,同一行內的數升序排列,相鄰兩個數用一個空格隔開。 其次,對於兩個不同的行,對應下標的數一一比較,字典序較小的排在前面(例如 1 3 5 7 排在 1 3 6 8 前面)。 資料範圍 n>0 , 0≤m≤n , n+(n−m)≤25 輸入樣例: 5 3 輸出樣例: 1 2 3 1 2 4 1 2 5 1 3 4 1 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5 思考題:如果要求使用非遞迴方法,該怎麼做呢?
首先看這道題,一樣熟悉的題目,只不過變成挑選m個數字出來。
最初的版本
import java.util.*; public class Main{ static int N = 30; static int n; static int m; static int[] st = new int[N]; static boolean[] vis = new boolean[N]; public static void main(String[] args){ Scanner sc = new Scanner(System.in); n = sc.nextInt(); m = sc.nextInt(); dfs(0); } public static void dfs(int u){ //u表示你在第幾層,同時也表示你在填第幾個空 //比如第0層,預設為0 //在第一層時,你挑選哪個來填第一個空 if(u == m){ for(int i = 0; i < m; i++){ System.out.printf("%d ",st[i]); } System.out.println(); return; } //i從1開始,所以每次遞迴進去的時候都會從首位開始找,如果被使用過了,就跳到下一個數 //所以就沒有思考有沒有升序的思考 for(int i = 1; i <= n; i++){ if(!vis[i]){ st[u] = i; vis[i] = true; dfs(u + 1); vis[i] = false; } } } }
一開始沒有考慮到升序的問題,所以就造成跟之前排列相似,u表示的層數,
然後我就想,如果要考慮升序的話,也就是說你每次遞迴進來的時候,都要根據上一個選的數字來挑選下一個數
比如你在2層的時候,在挑選第三個數時,我們用1 3 _舉例,當我們選完3時,我們為了升序肯定是不能選2的,所以這裡我有兩種思路
一種是你可以繼續遍歷2,但是得加個條件,就是上一個數要大於當前數才行,但這樣會浪費一次判斷
另一種是類似剪枝的思想,就是你儲存上一個的狀態值 + 1,在下一個遞迴時,就從那個位置開始遍歷,這樣就可以了
import java.util.*; /** *寫了這道題才開始理解的遞迴的含義 * 首先是 * * * * */ public class Main{ static int N = 30; static int n; static int m; static int[] st = new int[N]; static boolean[] vis = new boolean[N]; public static void main(String[] args){ Scanner sc = new Scanner(System.in); n = sc.nextInt(); m = sc.nextInt(); dfs(0,1); } public static void dfs(int u,int start){ if(u == m){ for(int i = 0; i < m; i++){ System.out.printf("%d ",st[i]); } System.out.println(); return ; } for(int i = start; i <= n; i++){ if(!vis[i]){ st[u] = i; vis[i] = true; //儲存此時選的數字 dfs(u + 1,i + 1); vis[i] = false; } } } }