1.题目描述
小兔的叔叔从外面旅游回来给她带来了一个礼物,小兔高兴地跑回自己的房间,拆开一看是一个棋盘。小兔有所失望。
只是没过几天发现了棋盘的好玩之处。从起点(0,0)走到终点(n,n)的最短路径数是C(2n,n),如今小兔又想假设不穿越对角线(但可接触对角线上的格点),这种路径数有多少?
小兔想了非常长时间都没想出来,如今想请你帮助小兔解决问题,对于你来说应该不难吧!
Input
每次输入一个数n(1<=n<=35),当n等于-1时结束输入。
Output
对于每一个输入数据输出路径数。详细格式看Sample。
Sample Input
1
3
12
-1
Sample Output
1 1 2
2 3 10
3 12 416024
2.解题思路
方法一:卡特兰数
这道题的规律是经典的卡特兰数。其实对于每一个递进的数字来说,比如5,思考之后可以分为1和4,2和3,3和2,4和1,还有两种直达的,把经过1格的方法乘以经过4格的方法总数,2格的方法总数乘以3格的方法总数……依次类推,就不难发现出规律,卡特兰数*2便是最后的结果,参考:https://blog.csdn.net/zhuge2017302307/article/details/79247532
这是卡特兰数的推倒公式:
来自百度百科,链接:点击打开链接
注意:此题只能用最上面的递推式推导,其他的都会溢出。
方法二:动态规划
走格点的迷宫,因为不能穿越对角线,所以到达终点只能向上或者向右走。画出图来可以得出,第一行只能由左边走来,而且对角线上的点只能由下面走来,到达其他点各有两种走法。所以我们事先把第一行所有点的值设为1,进行遍历,到达对角线时i==j, map[i][j]=map[i][j-1],只能接受从下面的点传递过来的走法。i!=j时,map[i][j]=map[i-1][j]+map[i][j-1],可以接受两边传递过来的走法。输出的是2*map[n][n]。参考:https://blog.csdn.net/blue_skyrim/article/details/49201335
3.代码实现
方法一:卡特兰数
#include <cstdio>
int main()
{
__int64 Catalan[40] = {0};
Catalan[0] = 1;
Catalan[1] = 1;
for (int i = 2 ; i <= 35 ; i++)
for (int j = 0 ; j <= i - 1 ; j++)
Catalan[i] += Catalan[j] * Catalan[i - 1 - j];
int num = 1;
int n;
while (~scanf ("%d",&n) && n != -1)
printf ("%d %d %I64d\n",num++,n,Catalan[n] * 2);
return 0;
}
方法二:动态规划
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int n;
long long map[40][40];
int main()
{
int i,j,cnt=1;;
while(cin>>n&&n!=-1)
{
memset(map,0,sizeof(map));
for(i=0;i<=n;++i)
map[0][i]=1;
for(i=1;i<=n;++i)
for(j=0;j<=i;++j)
{
if(i==j)
map[i][j]=map[i][j-1];
else
map[i][j]=map[i-1][j]+map[i][j-1];
}
printf("%d %d %I64d\n",cnt++,n,2*map[n][n]);
}
return 0;
}