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来解决是有好处,可以搜索完所有的可能性,但是这也带来了一个问题,也就是耗时的问题,假如只有两个平行状态的情况下,那么在每一次递归调用的时候都会分开两个叉去搜索,所以它是按照指数的方式来增长的,所以来说很耗时,所以虽然提交到代码平台上,对于不大的数字可以通过,但是比较大的数字那么肯定就超时了