算法提高 超级玛丽
时间限制:1.0s 内存限制:256.0MB
问题描述
大家都知道"超级玛丽"是一个很善于跳跃的探险家,他的拿手好戏是跳跃,但它一次只能向前跳一步或两步。有一次,他要经过一条长为n的羊肠小道,小道中有m个陷阱,这些陷阱都位于整数位置,分别是a
1,a
2,....a
m,陷入其中则必死无疑。显然,如果有两个挨着的陷阱,则玛丽是无论如何也跳过不去的。
现在给出小道的长度n,陷阱的个数及位置。求出玛丽从位置1开始,有多少种跳跃方法能到达胜利的彼岸(到达位置n)。
现在给出小道的长度n,陷阱的个数及位置。求出玛丽从位置1开始,有多少种跳跃方法能到达胜利的彼岸(到达位置n)。
输入格式
第一行为两个整数n,m
第二行为m个整数,表示陷阱的位置
第二行为m个整数,表示陷阱的位置
输出格式
一个整数。表示玛丽跳到n的方案数
样例输入
4 1
2
2
样例输出
1
数据规模和约定
40>=n>=3,m>=1
n>m;
陷阱不会位于1及n上
n>m;
陷阱不会位于1及n上
思路分析:
先判断是否有陷阱连接在一起1.是:直接输出0;
2.否:把相邻陷阱之间的点总数计算出来,然后首尾点集将所有计算数据相乘即可得到结果
现在我们剩下解决的问题是每一段的连续点有多少方案,我们可以假设5个点,那么计算到第5点有多
少种走法的时候,当最后是以1步到第5点的,则我们需要知道到达第4点的走法数,当最后是以2步到
第5点的,则我们需要知道到达第3点的走法数。于是可以知道,用斐波那契数列知识即可求解
注意:还需考虑当输入的陷阱位置超过范围的情况
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
int fib(int n);
int main(int argc, char const *argv[]) {
int n, m, num;
cin >> n >> m;
int mNum = m;
int trapNum[m+1];
int count[m+1];
for (int i = 1; i <= m; i++) {
cin >> num;
if(num < n)
{
trapNum[i] = num;
}
else
{
mNum--;
}
}
m = mNum;
bool flag = true;
int result = 0;
if(m == 1)
{
result = fib(trapNum[m]-1);
result *= fib(n-trapNum[m]);
cout << result << endl;
}
else
{
sort(trapNum+1, trapNum+m+1); //升序排序存放陷阱序号的数组
for (int i = 1; i < m; i++) {
if(trapNum[i+1] - trapNum[i] == 1)
{
cout << result << endl;
flag = false;
break;
}
else
{
count[i] = trapNum[i+1] - trapNum[i]-1;
}
}
if(flag == true)
{
result = 1;
count[0] = trapNum[1]-1;
count[m] = n-trapNum[m];
for (int i = 0; i <= m; i++) {
count[i] = fib(count[i]);
result *= count[i];
}
cout << result << endl;
}
}
return 0;
}
int fib(int n)
{
if(n==0 || n==1 || n==2)
{
return 1;
}
else
{
return fib(n-1) + fib(n-2);
}
}</span>