不是自己推出来的公式,看题解了才知道这个三维DP公式dp[i][j][k] = dp[i-1][j][k] + dp[i][j-1][k] + dp[i][j][k-1](i >= j >= k)
一看到这个题目,我的反应竟然是卡特兰数(一个有n个X和n个Y组成的字串,且所有的部分字串皆满足X的个数大于等于Y的个数。以下为长度为6的dyck words:XXXYYY XYXXYY XYXYXY XXYYXY XXYXYY),n<=60,即使不是卡特兰数,结果应该也会很大,所以要用到大数相加(真心的讨厌写大数相加相乘相除等的代码,磨蹭了些许时间,才写@_@,唉,什么时候自己写个有自己风格,至少自己以后也会认识它的模版,要用的时候直接拿来用就行了)。原来卡特兰数也可以用这种DP方式求的值啊~~~
代码如下:
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 char words[62][62][62][100]; 7 8 void add(char a[],char b[]) 9 { 10 int lena = strlen(a); 11 int lenb = strlen(b); 12 int len = min(lena,lenb); 13 int carry = 0; 14 int i; 15 for(i = 0;i < len;i ++) 16 { 17 int num = a[i] - '0' + b[i] - '0' + carry; 18 a[i] = num % 10 + '0'; 19 carry = num / 10; 20 } 21 while(i < lena) 22 { 23 int num = a[i] - '0' + carry; 24 a[i] = num % 10 + '0'; 25 carry = num / 10; 26 i ++; 27 } 28 29 while(i < lenb) 30 { 31 int num = b[i] - '0' + carry; 32 a[i] = num % 10 + '0'; 33 carry = num / 10; 34 i ++; 35 } 36 37 if(carry > 0) 38 { 39 a[i] = carry + '0'; 40 a[i+1] = '\0'; 41 } 42 else 43 { 44 a[i] = '\0'; 45 } 46 } 47 48 void dp() 49 { 50 memset(words,'\0',sizeof(words)); 51 words[0][0][0][0] = '1'; 52 words[0][0][0][1] = '\0'; 53 for(int i = 1;i < 62;i ++) 54 { 55 for(int j = 0;j <= i;j ++) 56 { 57 for(int k = 0;k <= j;k ++) 58 { 59 if(i - 1 >= j) 60 add(words[i][j][k],words[i-1][j][k]); 61 if(j-1 >= k) 62 add(words[i][j][k],words[i][j-1][k]); 63 if(k >= 1) 64 add(words[i][j][k],words[i][j][k-1]); 65 } 66 } 67 } 68 } 69 int main() 70 { 71 int n; 72 73 dp(); 74 while(cin >> n) 75 { 76 if(n == 0) 77 cout << "0" << endl; 78 else 79 { 80 for(int i = strlen(words[n][n][n])- 1;i >= 0;i --) 81 cout<<words[n][n][n][i]; 82 cout << endl; 83 } 84 cout << endl; 85 } 86 87 return 0; 88 }