题目:
如果每次可以往上爬1个或2个或3个台阶,爬楼梯过程中允许最多往下走一次,每次走1个台阶,从第0个台阶开始,爬到第n个台阶有多少种方案?
举例:
当n = 1时,有2种方案。
方案一:走1个台阶
方案二:走1个台阶,退1个台阶,再走1个台阶
当n = 2时,有6种方案
方案一:走1,走1
方案二:走1,走1,退1,走1
方案三:走2
方案四:走2,退1,走1
方案五:走1,退1,走1,走1
方案六:走1,退1,走2
思路:
爬到第n-1个台阶时总方案f(n-1)中分为已经往下走过一次和没有往下走过两种:
设已经往下走过一次的所有方案中最后一步是1个台阶为AA(n-1),2个台阶为BB(n-1),3个台阶为CC(n-1)。
设没有往下走过的所有方案中最后一步是1个台阶为A(n-1),2个台阶为B(n-1),3个台阶为C(n-1)。
即f(n-1)=AA(n-1)+BB(n-1)+CC(n-1)+A(n-1)+B(n-1)+C(n-1).
设爬到第n个台阶总方案数为f(n)(n > 3).
当每多一个台阶,分两部分处理:
在之前所有没有往下走过的方案中:
1)所有方案基础上,再爬1个台阶,即A(n-1)+B(n-1)+C(n-1)种方案.
2)所有方案基础上,再爬1个台阶,然后往下走1个台阶,再爬1个台阶。即A(n-1)+B(n-1)+C(n-1)种方案.
3)最后一次是爬1个台阶的方案,变成最后一步爬2个台阶。即A(n-1)种方案.
4)最后一次是爬1个台阶的方案,变成最后一步爬2个台阶,然后往下走1个台阶,再爬1个台阶。即A(n-1)种方案.
5)最后一次是爬2个台阶的方案,变成最后一步爬3个台阶。即B(n-1)种方案.
6)最后一次是爬2个台阶的方案,变成最后一步爬3个台阶,然后往下走1个台阶,再爬1个台阶。即B(n-1)种方案.
在之前所有已经往下走过一次的方案中:
1)所有方案基础上,再爬1个台阶,即AA(n-1)+BB(n-1)+CC(n-1)种方案.
2)最后一次是爬1个台阶的方案,变成最后一步爬2个台阶。即A(n-1)种方案.
3)最后一次是爬2个台阶的方案,变成最后一步爬3个台阶。即B(n-1)种方案.
由两部分所有处理步骤可知,
f(n) = 4A(n-1)+4B(n-1)+2C(n-1)+2AA(n-1)+2BB(n-1)+CC(n-1)
代码:
#define BIT_TOTAL 500
typedef struct{
char BigInt[BIT_TOTAL]; //BigInt[0]表示最高位
}BIGINT;
//将字符串反转
void Reverse(char nData[])
{
char temp;
for (int i = 0, j = strlen(nData)-1; (i != j) && (i - j != 1); i++, j--)
{
temp = nData[i];
nData[i] = nData[j];
nData[j] = temp;
}
}
//大整数加法
BIGINT Add(BIGINT first, BIGINT second)
{
BIGINT result;
memset(&result, 0, sizeof(BIGINT));
Reverse(first.BigInt);
Reverse(second.BigInt);
int temp = 0;
int bit = 0;
int length = strlen(first.BigInt) > strlen(second.BigInt) ? strlen(first.BigInt):strlen(second.BigInt);
for (int i = 0; i < length; i++)
{
if(first.BigInt[i] == '\0')
{
first.BigInt[i] = '0';
}
if(second.BigInt[i] == '\0')
{
second.BigInt[i] = '0';
}
temp = (first.BigInt[i]-'0') + (second.BigInt[i]-'0') + bit;
if (temp >= 10)
{//有进位
temp = temp % 10;
bit = 1;
}else
{//无进位
bit = 0;
}
result.BigInt[strlen(result.BigInt)] = char(temp + '0');
}
//判断是否要在最高位加一位数
if (bit == 1)
{
result.BigInt[strlen(result.BigInt)] = char(bit + '0');
}
Reverse(result.BigInt);
return result;
}
//nSteps为总台阶数
BIGINT ClimbStairs2(int nSteps)
{
BIGINT noStep_1; //noStep_1代表所有没有往下走过的方案中最后一步是1个台阶的方案
BIGINT noStep_2; //noStep_2代表所有没有往下走过的方案中最后一步是2个台阶的方案
BIGINT noStep_3; //noStep_3代表所有没有往下走过的方案中最后一步是3个台阶的方案
BIGINT yesStep_1; //yesStep_1代表所有已经往下走过一次的方案中最后一步是1个台阶的方案
BIGINT yesStep_2; //yesStep_2代表所有已经往下走过一次的方案中最后一步是2个台阶的方案
BIGINT yesStep_3; //yesStep_3代表所有已经往下走过一次的方案中最后一步是3个台阶的方案
BIGINT allSolution;
BIGINT tempCount;
memset(&noStep_1, 0, sizeof(BIGINT));
memset(&noStep_2, 0, sizeof(BIGINT));
memset(&noStep_3, 0, sizeof(BIGINT));
memset(&yesStep_1, 0, sizeof(BIGINT));
memset(&yesStep_2, 0, sizeof(BIGINT));
memset(&yesStep_3, 0, sizeof(BIGINT));
memset(&allSolution, 0, sizeof(BIGINT));
memset(&tempCount, 0, sizeof(BIGINT));
//只有一个台阶时的解决方案
noStep_1.BigInt[0] = '1';
yesStep_1.BigInt[0] = '1';
if(nSteps < 1)
{
allSolution.BigInt[0] = '0';
return allSolution;
}else if(nSteps == 1)
{
allSolution.BigInt[0] = '2';
return allSolution;
}else
{
allSolution.BigInt[0] = '2';
//从最少有2个台阶开始计算
for(int i = 2; i <= nSteps; i++)
{
//在已经往下走过一次的方案中最后一步是2个台阶的变成3个台阶
memcpy(&yesStep_3, &yesStep_2, sizeof(BIGINT));
//在已经往下走过一次的方案中最后一步是1个台阶的变成2个台阶
memcpy(&yesStep_2, &yesStep_1, sizeof(BIGINT));
//在所有已经往下走过一次的方案中,继续再走一步
//在所有没有往下走过的方案中,再走一步,然后退一步,再走一步
//在所有没有往下走过的方案中最后一步是1个台阶的变成2个台阶,然后退一步,再走一步
//在所有没有往下走过的方案中最后一步是2个台阶的变成3个台阶,然后退一步,再走一步
memcpy(&yesStep_1, &allSolution, sizeof(BIGINT));
memcpy(&yesStep_1, &Add(yesStep_1, noStep_1), sizeof(BIGINT));
memcpy(&yesStep_1, &Add(yesStep_1, noStep_2), sizeof(BIGINT));
//在所有没有往下走过的方案中,继续再走一步
memcpy(&tempCount, &Add(noStep_1, noStep_2), sizeof(BIGINT));
memcpy(&tempCount, &Add(tempCount, noStep_3), sizeof(BIGINT));
//在所有没有往下走过的方案中最后一步是2个台阶的变成3个台阶
memcpy(&noStep_3, &noStep_2, sizeof(BIGINT));
//在所有没有往下走过的方案中最后一步是1个台阶的变成2个台阶
memcpy(&noStep_2, &noStep_1, sizeof(BIGINT));
memcpy(&noStep_1, &tempCount, sizeof(BIGINT));
memcpy(&allSolution, &Add(noStep_1, noStep_2), sizeof(BIGINT));
memcpy(&allSolution, &Add(allSolution, noStep_3), sizeof(BIGINT));
memcpy(&allSolution, &Add(allSolution, yesStep_1), sizeof(BIGINT));
memcpy(&allSolution, &Add(allSolution, yesStep_2), sizeof(BIGINT));
memcpy(&allSolution, &Add(allSolution, yesStep_3), sizeof(BIGINT));
}
return allSolution;
}
}
原始题目:如果每次可以往上爬1个或2个或3个台阶,不能往下走,从第0个台阶开始,爬到第n个台阶有多少种方案?
答案:爬楼梯问题
扩展题目:如果每次可以往上爬1个或2个或3个台阶,爬楼梯过程中允许最多往下走k次,每次走1个台阶,从第0个台阶开始,爬到第n个台阶有多少种方案?
答案:爬楼梯问题豪华版