骨牌铺方格 (sdut oj)

本文介绍了一个经典的算法问题——使用1×2的骨牌铺满2×n的长方形方格,并提供了完整的C语言实现代码。通过递推公式求解不同长度下铺放方案的总数。


骨牌铺方格

Time Limit: 1000MS  Memory Limit: 32768KB


Problem Description
在2×n的一个长方形方格中,用一个1× 2的骨牌铺满方格,输入n ,输出铺放方案的总数. 例如n=3时,为2× 3方格,骨牌的铺放方案有三种,如下图: 

Input
输入数据由多行组成,每行包含一个整数n,表示该测试实例的长方形方格的规格是2×n (0< n<=50)。

Output
对于每个测试实例,请输出铺放方案的总数,每个实例的输出占一行。

Example Input
1
3
2

Example Output
1
3
2
Hint
hdoj2046 有链接提示的题目请先去链接处提交程序,AC后提交到SDUTOJ中,以便查询存档。
Author
HDU LCY






参考代码



#include<stdio.h>
int main()
{
    int i,n;
    int long long a[50];
    a[0] = 1;
    a[1] = 2;
    while(~scanf("%d",&n))
    {
        for( i = 2; i < n; i++ )
        {
            a[i] = a[i-1] + a[i-2];
        }
        printf("%lld\n",a[n-1]);
    }
    return 0;
}


<think> 根据提供的引用内容,用户需要查找用C语言实现骨牌方格问题的递归函数。引用[2]中已经给出了一个C语言递归函数,该函数用于计算满1×n长方形的不同法数。 函数定义如下: - 当n=1时,只有一种法(使用1个1×1骨牌),返回1。 - 当n=2时,有三种法(两个1×1、一个1×2),返回3。 - 当n>=3时,递归公式为:`function(n) = 2 * function(n-2) + function(n-1)` 在引用[2]的代码中,函数名为`function`,它接受一个整数n,返回法数目。 因此,我们可以直接提取这个递归函数。注意,引用[2]中给出的代码是完整的程序,包括主函数,但用户只需要递归函数部分。 所以,递归函数的C语言实现为: ```c int dominoTiling(int n) { if (n == 1) return 1; if (n == 2) return 3; return 2 * dominoTiling(n-2) + dominoTiling(n-1); } ``` 注意:原代码中函数名为`function`,这里为了可读性,将函数名改为`dominoTiling`,但实际使用中可以根据需要命名。 另外,需要说明的是,这个递归公式的推导基于以下考虑: - 当第n列放置一个1×1骨牌时,前面n-1列有`function(n-1)`种法。 - 当第n列与第n-1列一起放置一个1×2骨牌时(横放),前面n-2列有`function(n-2)`种法。但是注意,1×2骨牌也可以竖放,但这里横放和竖放实际上是一样的,因为骨牌只有三种规格,而1×2骨牌只有一种放置方式(横放覆盖两列)。然而,观察递推关系,实际上这里还考虑了1×3骨牌?但题目中给出了三种骨牌(1×1, 1×2, 1×3)。 重新审视问题:题目中允许使用1×1, 1×2, 1×3三种骨牌。所以递推关系需要重新考虑。 引用[1]中说明当n=3时,有4种法。而引用[2]中的递归函数计算n=3时:`function(3)=2*function(1)+function(2)=2*1+3=5`,但实际应该是4种?这里存在矛盾。 因此,我们需要重新推导递推关系。 设dp[n]表示满1×n方格的方法数。 - 考虑最后一步: 1. 最后放置一个1×1骨牌:则前n-1格有dp[n-1]种方法。 2. 最后放置一个1×2骨牌(横跨第n-1和n列):则前n-2格有dp[n-2]种方法。 3. 最后放置一个1×3骨牌(横跨第n-2, n-1, n列):则前n-3格有dp[n-3]种方法。 因此,递推关系应该是:dp[n] = dp[n-1] + dp[n-2] + dp[n-3] 初始条件: - dp[0] = 1(空棋盘,一种方法:什么都不放) - dp[1] = 1(一个1×1骨牌) - dp[2] = 2(两个1×1骨牌或一个1×2骨牌)?不对,因为题目中n=2时引用[1]没有直接给出,但引用[2]中给出n=2返回3。而题目中n=3有4种。 根据题目描述,n=3时有4种法。我们枚举n=3: 1. 三个1×1 2. 一个1×1和一个1×2(1×2可以在前两个或后两个,所以有两种:1×2在前两列,后面一个1×1;或者一个1×1在最前面,后面一个1×2) 3. 一个1×3 所以一共4种。 按照递推关系:dp[3]=dp[2]+dp[1]+dp[0] 我们需要dp[0]=1, dp[1]=1, dp[2]=? dp[2]:两种法(两个1×1;一个1×2)。所以dp[2]=2。 则dp[3]=dp[2]+dp[1]+dp[0]=2+1+1=4,符合。 但是引用[2]中给出的递归函数是: n=1 -> 1 n=2 -> 3 n>=3: 2*f(n-2)+f(n-1) 这个函数计算n=3:2*1+3=5,与题目给出的4种不符。 因此,引用[2]中的递归函数似乎与题目要求不符。题目要求的是三种骨牌(1×1,1×2,1×3),而引用[2]中的函数可能是针对另一种情况(比如只有1×1和1×2)?但引用[2]中函数计算n=2返回3,而标准1×2骨牌问题中(只有1×1和1×2)n=2应该是2种(两个1×1或一个1×2)?为什么返回3? 实际上,引用[2]中函数可能是针对1×2骨牌问题(使用1×1和1×2)的另一种递推,但标准递推是斐波那契:f(n)=f(n-1)+f(n-2),其中f(1)=1, f(2)=2。而这里f(2)=3,所以可能不是同一问题。 再看引用[1]的题目描述:有1×n,用1×1,1×2,1×3三种骨牌,求法数。且n=3时有4种。 因此,正确的递推关系应该是:dp[n] = dp[n-1] + dp[n-2] + dp[n-3] 初始条件: dp[0] = 1 dp[1] = 1 dp[2] = 2 那么,递归函数应该写为: ```c int dominoTiling(int n) { if (n == 0) return 1; if (n == 1) return 1; if (n == 2) return 2; return dominoTiling(n-1) + dominoTiling(n-2) + dominoTiling(n-3); } ``` 但是,引用[2]中的代码和题目描述不一致。我们需要按照题目描述(引用[1])来写递归函数。 因此,正确的C语言递归函数实现应该是上述代码。 然而,引用[1]中n=3时是4种,用这个函数计算n=3: dominoTiling(3) = dominoTiling(2)+dominoTiling(1)+dominoTiling(0)=2+1+1=4,符合。 所以,用户需要的是针对有三种骨牌(1×1,1×2,1×3)的骨牌方格问题的递归函数,而不是引用[2]中的函数。 结论:根据引用[1]的问题描述,我们推导出正确的递推关系,并写出递归函数。 注意:这个递归函数在n较大时效率较低(指数级),因为存在大量重复计算。在实际应用中,可以使用动态规划(记忆化递归)来优化。但用户目前只需要递归函数。 所以,最终答案如下: </think> 根据骨牌方格问题的描述和引用内容,我将提供C语言递归函数的实现及解析。问题的核心是使用1×1、1×2和1×3三种骨牌满1×n长方形,计算不同法数量。 ### C语言递归函数实现 ```c #include <stdio.h> // 骨牌法递归函数 int dominoTiling(int n) { // 基准情况处理 if (n == 0) return 1; // 空法算1种 if (n == 1) return 1; // 只有1×1一种法 if (n == 2) return 2; // 两种法: 两个1×1 或 一个1×2 // 递归关系: f(n) = f(n-1) + f(n-2) + f(n-3) return dominoTiling(n-1) + dominoTiling(n-2) + dominoTiling(n-3); } int main() { int n; printf("输入长方形长度n: "); scanf("%d", &n); printf("法数量: %d\n", dominoTiling(n)); return 0; } ``` ### 递归原理说明 1. **基准情况**(直接求解): - $n=0$:空长方形,视为1种法(数学定义) - $n=1$:只能使用1×1骨牌 → **1种法** - $n=2$:可两个1×1 或 一个1×2 → **2种法** 2. **递归关系**(分治策略): 对于$n≥3$,考虑最后一步操作: - 最后放置$1×1$骨牌:剩余$n-1$长度 → $f(n-1)$种法 - 最后放置$1×2$骨牌:剩余$n-2$长度 → $f(n-2)$种法 - 最后放置$1×3$骨牌:剩余$n-3$长度 → $f(n-3)$种法 因此得到递推公式: $$f(n) = f(n-1) + f(n-2) + f(n-3)$$ ### 示例验证 当$n=3$时(引用[1]案例): ```c f(3) = f(2) + f(1) + f(0) = 2 + 1 + 1 = 4 ``` 结果符合题目描述的4种法(图5.3)。 ### 复杂度分析 - **时间复杂度**:$O(3^n)$(指数级,存在重复计算) - **空间复杂度**:$O(n)$(递归栈深度) > **优化建议**:实际应用中建议使用动态规划(DP)将复杂度优化至$O(n)$,或矩阵快速幂优化至$O(\log n)$[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值