dfs_鋪瓷磚
1. 問題描述:
時間限制:5000ms
單點時限:1000ms
記憶體限制:256MB
描述
有一長度為N(1<=N<=1000)的地板,給定兩種不同瓷磚:一種長度為1,另一種長度為2,數目不限。
要將這個長度為N的地板鋪滿,一共有多少種不同的鋪法?
為了防止溢位,請將結果Mod 1000000007
輸入
一個整數N。(1 <= N <= 1000)
輸出
鋪法的數量Mod 1000000007
樣例輸入
3
樣例輸出
3
2. 一看到上面的題目是不是有點似曾相識,跟小白上樓梯的情況類似,只不過是換了一種場景,但是本質上是一樣的,我們可以使用遞推來解決,我們可以把前面的的瓷磚都鋪設好,那麼假如只剩下長度為2那麼有兩種鋪設的方法,假如剩下長度為1那麼就有一種鋪設的方法,其它的長度也類似像這樣分析,具體的程式碼如下:
import java.util.Scanner;
public class Main {
//這道題目跟上樓梯的題目類似
static int N;
static long count = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
dfs(N);
System.out.println(count);
sc.close();
}
private static long dfs(int k) {
if(k == 1) return count += 1;
if(k == 2) return count += 2;
return dfs(k - 1) + dfs(k - 2);
}
}
除了使用遞推的方法,我們還可以使用dfs來的解決,其中比較好的是使用dfs可以記錄下中間的過程,把所有的組合的情況都記錄下來,其中當我們設定dfs出口的時候,當長度等於目標長度的時候就return,假如這個時候沒有return的話,那麼就還需要再搜尋一下它的下一層的元素然後再長度大於目標長度的時候再退出來,那麼就會導致不必要的搜尋,所以等於目標長度的時候就return了
還需要注意的是記錄中間的過程需要溯,這裡我們使用動態的陣列List來記錄中間的過程,即當退回到這一層的時候把這一層原來加入的最後一個元素給清除掉,然後退回到另外一個平行狀態下再清除掉原來加入的元素那麼其中的List加入的元素才是正確的,這也就是我們所說的回溯,當我們退回到平行狀態下,嘗試另外一個元素的時候假如這個平行狀態對下一個平行狀態有影響那麼就需要進行回溯,那麼才可以得到正確的結果
3. 具體的程式碼如下:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main{
static int N;
static long count = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
List<Integer> listInput = new ArrayList<Integer>();
dfs(0, listInput);
System.out.println(count % 1000000007);
sc.close();
}
private static void dfs(int k, List<Integer> listInput){
if(k == N){
System.out.println(listInput);
count++;
return;
}
if(k > N){
return;
}
listInput.add(2);
dfs(k + 2, listInput);
listInput.remove(listInput.size() - 1);
listInput.add(1);
dfs(k + 1, listInput);
listInput.remove(listInput.size() - 1);
}
}
使用dfs來解決是有好處,可以搜尋完所有的可能性,但是這也帶來了一個問題,也就是耗時的問題,假如只有兩個平行狀態的情況下,那麼在每一次遞迴呼叫的時候都會分開兩個叉去搜索,所以它是按照指數的方式來增長的,所以來說很耗時,所以雖然提交到程式碼平臺上,對於不大的數字可以通過,但是比較大的數字那麼肯定就超時了