题目地址:
http://acm.hdu.edu.cn/showproblem.php?pid=2067
题目描述:
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
小兔的叔叔从外面旅游回来给她带来了一个礼物,小兔高兴地跑回自己的房间,拆开一看是一个棋盘,小兔有所失望。不过没过几天发现了棋盘的好玩之处。从起点( 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
题目分析:
假设小兔的棋盘是 8 × 8 的 ( 当然你也可以假设是其他 )。如下图:
箭头方向表示从该格子下一步能去的格子。因为不能穿越对角线,所有对角线上的格子只有进去的箭头,没有出来的箭头。
观察上图你就可以发现,其实这是一张关于对角线对称的图。所有我们只要求一个方向的值,然后乘以2即可。
我们就拿下三角来考虑。不难发现,所有在0列上的格子,路径数都是 1 (只能从上面过来)。
而其他格子则都是由上、左两个方向过来,即: f(i, j) = f(i - 1, j) + f(i, j - 1);
另外 f(i, i) = f(i, j - 1) 或者 f(i, i) = f( i-1, j ) ;
箭头方向表示从该格子下一步能去的格子。因为不能穿越对角线,所有对角线上的格子只有进去的箭头,没有出来的箭头。
![](https://i-blog.csdnimg.cn/blog_migrate/c63b7f277f1bd544f63340b4db64dfe6.jpeg)
观察上图你就可以发现,其实这是一张关于对角线对称的图。所有我们只要求一个方向的值,然后乘以2即可。
我们就拿下三角来考虑。不难发现,所有在0列上的格子,路径数都是 1 (只能从上面过来)。
而其他格子则都是由上、左两个方向过来,即: f(i, j) = f(i - 1, j) + f(i, j - 1);
另外 f(i, i) = f(i, j - 1) 或者 f(i, i) = f( i-1, j ) ;
代码如下:
MiYu原创, 转帖请注明 : 转载自 ______________白白の屋
#include < iostream >
using namespace std;
typedef long long int64;
int64 f[ 37 ][ 37 ];
int main()
{
int ca = 0 ;
int N;
while ( cin >> N , N + 1 )
{
++ ca;
for ( int i = 1 ;i <= N; ++ i )
{
f[ 0 ][i] = 1 ;
}
for ( int i = 1 ; i < N; ++ i )
{
for ( int j = i; j <= N; ++ j )
{
if ( i == j )
{
f[i][j] = f[i - 1 ][j];
}
else
{
f[i][j] = f[i - 1 ][j] + f[i][j - 1 ];
}
}
}
printf( " %d %d %I64d\n " , ca, N, 2 * f[N - 1 ][N] );
}
return 0 ;
}
#include < iostream >
using namespace std;
typedef long long int64;
int64 f[ 37 ][ 37 ];
int main()
{
int ca = 0 ;
int N;
while ( cin >> N , N + 1 )
{
++ ca;
for ( int i = 1 ;i <= N; ++ i )
{
f[ 0 ][i] = 1 ;
}
for ( int i = 1 ; i < N; ++ i )
{
for ( int j = i; j <= N; ++ j )
{
if ( i == j )
{
f[i][j] = f[i - 1 ][j];
}
else
{
f[i][j] = f[i - 1 ][j] + f[i][j - 1 ];
}
}
}
printf( " %d %d %I64d\n " , ca, N, 2 * f[N - 1 ][N] );
}
return 0 ;
}
另外看别人的解题报告说这个是卡特兰数 ( 详细请查看 <<卡特兰数>> ), 其实现在还不理解, 分析如下:
Catalan数。。
令h( 1 )= 1 ,h( 0 ) = 1 ,catalan数满足递归式:
h(n) = h( 0 ) * h(n - 1 ) + h( 1 ) * h(n - 2 ) +
+
h(n
-
1
)h(
0
) (其中n
>=
2
)
另类递归式:
h(n) = (( 4 * n - 2 ) / (n + 1 )) * h(n - 1 );
该递推关系的解为:
h(n) = C(2n,n) / (n + 1 ) (n = 1 , 2 , 3 ,…)
令h( 1 )= 1 ,h( 0 ) = 1 ,catalan数满足递归式:
h(n) = h( 0 ) * h(n - 1 ) + h( 1 ) * h(n - 2 ) +
![](https://i-blog.csdnimg.cn/blog_migrate/918e8df969f9f8c8d002f25cda86cade.gif)
另类递归式:
h(n) = (( 4 * n - 2 ) / (n + 1 )) * h(n - 1 );
该递推关系的解为:
h(n) = C(2n,n) / (n + 1 ) (n = 1 , 2 , 3 ,…)
附卡特兰代码:
#include
<
stdio.h
>
int main()
{
__int64 a[ 37 ][ 37 ] = { 0 };
int i,j,n,t = 0 ;
a[ 0 ][ 0 ] = 0 ;
a[ 0 ][ 1 ] = 1 ;
a[ 1 ][ 1 ] = 2 ;
for (i = 2 ;i < 37 ;i ++ )
{
a[i][ 0 ] = 1 ;
for (j = 1 ;j < i - 1 ;j ++ )
a[i][j] = a[i][j - 1 ] + a[i - 1 ][j];
a[i][i - 1 ] = a[i][i - 2 ] + a[i - 1 ][i - 1 ] / 2 ;
a[i][i] = 2 * a[i][i - 2 ] + a[i - 1 ][i - 1 ];
}
while (scanf( " %d " , & n) && n !=- 1 )
{
printf( " %d %d %I64d\n " , ++ t,n,a[n][n]);
}
return 0 ;
}
int main()
{
__int64 a[ 37 ][ 37 ] = { 0 };
int i,j,n,t = 0 ;
a[ 0 ][ 0 ] = 0 ;
a[ 0 ][ 1 ] = 1 ;
a[ 1 ][ 1 ] = 2 ;
for (i = 2 ;i < 37 ;i ++ )
{
a[i][ 0 ] = 1 ;
for (j = 1 ;j < i - 1 ;j ++ )
a[i][j] = a[i][j - 1 ] + a[i - 1 ][j];
a[i][i - 1 ] = a[i][i - 2 ] + a[i - 1 ][i - 1 ] / 2 ;
a[i][i] = 2 * a[i][i - 2 ] + a[i - 1 ][i - 1 ];
}
while (scanf( " %d " , & n) && n !=- 1 )
{
printf( " %d %d %I64d\n " , ++ t,n,a[n][n]);
}
return 0 ;
}