HDOJ HDU 2067 小兔的棋盘 ACM 2067 IN HDU

MiYu原创, 转帖请注明 : 转载自 ______________白白の屋

题目地址:
         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

题目分析:
假设小兔的棋盘是 8 × 8 的 ( 当然你也可以假设是其他 )。如下图:
箭头方向表示从该格子下一步能去的格子。因为不能穿越对角线,所有对角线上的格子只有进去的箭头,没有出来的箭头。


观察上图你就可以发现,其实这是一张关于对角线对称的图。所有我们只要求一个方向的值,然后乘以2即可。
我们就拿下三角来考虑。不难发现,所有在0列上的格子,路径数都是  (只能从上面过来)。
而其他格子则都是由上、左两个方向过来,即: 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 ;
}

另外看别人的解题报告说这个是卡特兰数 ( 详细请查看  <<卡特兰数>>  ), 其实现在还不理解, 分析如下:
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 ,…)

附卡特兰代码:
#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 ;
}

转载于:https://www.cnblogs.com/MiYu/archive/2010/08/18/1802479.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值