1024 瓷砖问题再讨论(java)

博客探讨了1024瓷砖问题的解决方案,通过递归和数学分析,提出使用动态规划的方法来求解。文章介绍了动态规划的状态转移方程,并展示了如何通过观察和归纳得出这些方程。虽然给出了程序实现,但强调动态规划的理解和应用需要深入思考。

瓷砖铺放问题题解友情链接

瓷砖问题再讨论

问题描述
  有一长度为N(1<=N<=10)的地板,给定三种不同瓷砖:一种长度为1,一种长度为2,另一种长度为3,数目不限。要将这个长度为N的地板铺满,并且要求长度为1的瓷砖不能相邻,一共有多少种不同的铺法?在所有的铺设方法中,一共用了长度为1的瓷砖多少块?
  例如,长度为4的地面一共有如下4种铺法,并且,一共用了长度为1的瓷砖4块:
  4=1+2+1
  4=1+3
  4=2+2
  4=3+1
  编程求解上述问题。
输入格式
  只有一个数N,代表地板的长度
输出格式
  第一行有一个数,代表所有不同的瓷砖铺放方法的总数。
  第二行也有一个数,代表这些铺法中长度为1的瓷砖的总数
样例输入
4
样例输出
4
4


题目分析:递归问题+数学问题(其实最后发现尝试用动态规划也可以叭啦啦~)

算法分析:一开始吧,我也没想到动态规划这回事,就先暴力手写,列出前几个情况呗:

长度为1       
长度为2    2    
长度为3    1+2     2+1     3       
长度为4    1+3    1+2+1    2+2     3+1     
长度为5     1+2+2     1+3+1      2+1+2     2+2+1     2+3      3+2     
长度为6     1+2+1+2     1+2+2+1     1+2+3     1+3+2      2+1+2+1     2+1+3     2+2+2     2+3+1      3+1+2     3+2+1     3+3     

写着写着我就发现事情好像并不简单的样子,可能和我列这些情况的顺序有点关系。于是我就决定尝试——徒眼找一波规律试试。还别说.....真给看出点门道。

我们把第一块为长度为1的瓷砖的方案数用红色表示,其他方案用绿色表示。(不要纠结为什么选这两个颜色,耀眼呗,就是耀眼!) 好的,现在引入二维数组way[ ][ ],way[ i ][ 1 ]表示长度为i且第一块为长度为1的瓷砖的方案数(红的那些),way[ i ][ 0 ]当然就表示长度为i且第一块为长度不为1的瓷砖的方案数了(绿的那些)。看出什么门道了呢,就是way[ i ][ 1 ] = way[ i - 1 ][ 0 ],那么 way[ i ][ 0 ]呢,我还是决定继续徒眼找(就是不信邪,总觉得应该是简单题,想暴力一把)。有意思的是,就这么给看出来了,于是我把看出点的规律整理成式子,也就是way[i][0] = way[i - 2][0] + way[i - 2][1] + way[i - 3][0] + way[i - 3][1] 。

但是问题中还要求输出长度为1的瓷砖总数,那就再引入数组num[ ][ ] ,继续找呗,这时候光靠看已经有点费劲了,于是把两个数组的前几种情况列下来,大同小异,规律是num[i][1] = way[i][1] + num[i - 1][0] 和 num[i][0] = num[i - 2][0] + num[i - 2][1] + num[i - 3][0] + num[i - 3][1]。可以对照下面研究。

way[1][1]=1 way[1][0]=0      num[1][1]=1 num[1][0]=0    

way[2][1]=0 way[2][0]=1      num[2][1]=0 num[2][0]=0  
  
way[3][1]=1 way[3][0]=2      num[3][1]=1 num[3][0]=1  
  
way[4][1]=2 way[4][0]=2      num[4][1]=3 num[4][0]=1   
 
way[5][1]=2 way[5][0]=4      num[5][1]=3 num[5][0]=2   
 
way[6][1]=4 way[6][0]=7      num[6][1]=6 num[6][0]=6   

然后就写程序验证就行了。(怎么感觉我把这题做成了小学找规律题...)

算法设计:

import java.util.*;
class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        sc.close();
        int[][] way = new int[11][2];
        int[][] num = new int[11][2];
        way[1][0] = way[2][1] = 0;
        way[1][1] = way[2][0] = way[3][1] = 1;
        way[3][0] = 2;
        for (int i = 4; i <= 10; i++) {
            way[i][0] = way[i - 2][0] + way[i - 2][1] + way[i - 3][0] + way[i - 3][1];
            way[i][1] = way[i - 1][0];
        }
        num[1][0] = num[2][1] = num[2][0] = 0;
        num[1][1] = num[3][1] = num[3][0] = 1;
        for (int i = 4; i <= 10; i++) {
            num[i][0] = num[i - 2][0] + num[i - 2][1] + num[i - 3][0] + num[i - 3][1];
            num[i][1] = way[i][1] + num[i - 1][0];
        }
        int ways = way[N][0] + way[N][1];
        int nums = num[N][0] + num[N][1];
        System.out.println(ways);
        System.out.println(nums);
    }
}


Emmmmm.....程序没有错,但是我们需要反思一下,这两组动态规划状态式的本质是什么,毕竟不是很多题目可以这样找出规律的,深思熟路了很久,大概想通了。但是鉴于我的第一篇k好数——动态规划入门题解,写得实在是太久太详细了,耗时耗力,这里的动态规划不再做深入解析,动态规划都是要靠悟出来的,多思考当然是好的是吧。还没有入门的这里再放个友情链接叭。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值