Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 12794 Accepted Submission(s): 6399 Problem Description 小兔的叔叔从外面旅游回来给她带来了一个礼物,小兔高兴地跑回自己的房间,拆开一看是一个棋盘,小兔有所失望。不过没过几天发现了棋盘的好玩之处。从起点(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
Author Rabbit
Source
Recommend lcy | We have carefully selected several similar problems for you: 2064 2065 1133 2068 1267 |
思路:可以用dp来做(在下面),也可以用卡特兰数来做,说一下卡特兰数吧,
n*n的方格地图中,从一个角到另外一个角,不跨越对角线的路径数为h(n).例如, 4×4方格地图中的路径有:
这道题目可以理解为 横着走的和竖着走的 组成了卡特兰数的第一个递推公式:
h(n)=h(0)*h(n-1)+h(1)*h(n-2)+...+h(n-1)*h(0).
算式运行中从不存在大于n的情况,所以,算的是下面的那一块,
还有就是这个棋盘并不只有下面的部分,上面的部分和这个一样的,对称着来。
卡特兰数公式及例题应用总结,可以看一下这个总结中的例题9,和这个一样的,
别忘了 long long.....
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#define N 40
#define ll long long
using namespace std;
ll f[N]; //不开long long 是错误的。。。。
int main()
{
f[0]=f[1]=1;
for(int i=2;i<=35;i++)
{
for(int j=0;j<=i-1;j++)
f[i]+=f[j]*f[i-j-1];
}
int num=1,n;
while(cin>>n&&n!=-1)
{
printf("%d %d %lld\n",num++,n,f[n]*2);
}
return 0;
}
还可以用递推的方法来做,
思路就这样,基本就这么来的,
递推公式:f[i][j]=f[i-1][j]+f[i][j-1];
不过这个也是算的一半,另一半也差不多的,就是这个的话,不会有大于i的情况,
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#define N 40
#define ll long long
using namespace std;
ll f[N][N];
int main()
{
for(int i=0;i<=35;i++)
f[i][0]=1;
for(int i=0;i<=35;i++)
for(int j=1;j<=i;j++)
f[i][j]=f[i-1][j]+f[i][j-1];
int num=1,n;
while(cin>>n&&n!=-1)
{
printf("%d %d %lld\n",num++,n,f[n][n]*2);
}
return 0;
}