Posted on 2010-08-07 21:37
MiYu 閱讀(1181)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
ACM ( 數(shù)論 ) 、
ACM ( 組合 )
MiYu原創(chuàng), 轉(zhuǎn)帖請(qǐng)注明 : 轉(zhuǎn)載自 ______________白白の屋
題目地址:
http://acm.hdu.edu.cn/showproblem.php?pid=2067
題目描述:
Problem Description
小兔的叔叔從外面旅游回來給她帶來了一個(gè)禮物,小兔高興地跑回自己的房間,拆開一看是一個(gè)棋盤,小兔有所失望。不過沒過幾天發(fā)現(xiàn)了棋盤的好玩之處。從起點(diǎn)(0,0)走到終點(diǎn)(n,n)的最短路徑數(shù)是C(2n,n),現(xiàn)在小兔又想如果不穿越對(duì)角線(但可接觸對(duì)角線上的格點(diǎn)),這樣的路徑數(shù)有多少?小兔想了很長(zhǎng)時(shí)間都沒想出來,現(xiàn)在想請(qǐng)你幫助小兔解決這個(gè)問題,對(duì)于你來說應(yīng)該不難吧!
Input
每次輸入一個(gè)數(shù)n(1<=n<=35),當(dāng)n等于-1時(shí)結(jié)束輸入。
Output
對(duì)于每個(gè)輸入數(shù)據(jù)輸出路徑數(shù),具體格式看Sample。
Sample Input
1
3
12
-1
Sample Output
1 1 2
2 3 10
3 12 416024
題目分析:
假設(shè)小兔的棋盤是 8 × 8 的 ( 當(dāng)然你也可以假設(shè)是其他 )。如下圖:
箭頭方向表示從該格子下一步能去的格子。因?yàn)椴荒艽┰綄?duì)角線,所有對(duì)角線上的格子只有進(jìn)去的箭頭,沒有出來的箭頭。

觀察上圖你就可以發(fā)現(xiàn),其實(shí)這是一張關(guān)于對(duì)角線對(duì)稱的圖。所有我們只要求一個(gè)方向的值,然后乘以2即可。
我們就拿下三角來考慮。不難發(fā)現(xiàn),所有在0列上的格子,路徑數(shù)都是
1 (只能從上面過來)。
而其他格子則都是由上、左兩個(gè)方向過來,即:
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原創(chuàng), 轉(zhuǎn)帖請(qǐng)注明 : 轉(zhuǎn)載自 ______________白白の屋
#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;
}
另外看別人的解題報(bào)告說這個(gè)是卡特蘭數(shù) ( 詳細(xì)請(qǐng)查看
<<卡特蘭數(shù)>> ), 其實(shí)現(xiàn)在還不理解, 分析如下:
Catalan數(shù)。。
令h(1)=1,h(0)=1,catalan數(shù)滿足遞歸式:
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);
該遞推關(guān)系的解為:
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;
}