题意描述很简单,阅读无障碍。当然直接递归,会有很多重复计算,效率必然很低。优化势在必行,关键如何优化。
首先想到的当然是动态规划。DP的优势就在于打表,从而减少重复计算。况且,很少有题目会把状态转换方程赤裸裸的给出来。这里的难点在于:不知道怎样由初始状态,根据状态方程,一步一步往下计算,直至问题求解。
状态方程:
(1)if a <= 0 or b <= 0 or c <= 0, then w(a, b, c) = 1
(2)if a > 20 or b > 20 or c > 20, then w(a, b, c) = w(20, 20, 20)
(3)if a < b and b < c, then w(a, b, c) = w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c)
(4)otherwise,w(a, b, c) = w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1)
如图所示:首先,由状态方程(1)(2),可以把要求的点限定在图中的长方体内。初始时,点( 0, 0, 0 )可知,由状态方程(1)可知,ab平面、ac平面、bc平面内的点都可知。然后,W( 1, X, X )根据状态方程(4)可以转换为W( 0, X, X )。同理W( 2, X, X )à W( 1, X, X )。这样,平行于bc平面的切面(图中红线所示, a为int,最多有20个)依次可知。在同一个切面内,如果满足条件,则可使用状态方程(3)
具体编程实现时,可以用一个全局变量dp[a][b][c], 这样即使在不同的测试用例之间,也可以避免重复计算。
除了DP,也可以直接用递归。只不过为了避免重复,也需要打表。这样在递归调用前,可以先查表,如果已经计算过,则直接返回。
#include <iostream> using namespace std; //***********************常量定义***************************** const int NUM = 22; //*********************自定义数据结构************************* //********************题目描述中的变量************************ //**********************算法中的变量************************** int dp[NUM][NUM][NUM]; bool visit[NUM][NUM][NUM]; //***********************算法实现***************************** //记忆化搜索 递归形式的实现 int RecSolve( int a, int b, int c ) { if( a<=0 || b<=0 || c<=0 ) { return 1; } if( a>20 || b>20 || c>20 ) { return RecSolve( 20, 20, 20 ); } //先查找,看以前是否计算过 if( visit[a][b][c] ) { return dp[a][b][c]; } visit[a][b][c] = true; if( a<b && b<c ) { return dp[a][b][c] = RecSolve(a, b, c-1) + RecSolve(a, b-1, c-1) - RecSolve(a, b-1, c); } else { return dp[a][b][c] = RecSolve(a-1, b, c) + RecSolve(a-1, b-1, c) + RecSolve(a-1, b, c-1) - RecSolve(a-1, b-1, c-1); } } //DP实现 int DPSolve( int a, int b, int c ) { if( a<0 || b<0 || c<0 ) { a = b = c = 0; } if( a>20 || b>20 || c>20 ) { a = b = c = 20; } //a ,b ,c可能为负,必须放在if( a<0 || b<0 || c<0 )之后 if( visit[a][b][c] ) { return dp[a][b][c]; } int x, y, z; for( z=0; z<=a; z++ ) { for( x=0; x<=b; x++ ) { for( y=0; y<=c; y++ ) { if( z==0 || x==0 || y==0 ) { dp[z][x][y] = 1; } else if( z<x && x<y ) { dp[z][x][y] = dp[z][x][y-1] + dp[z][x-1][y-1] - dp[z][x-1][y]; } else { dp[z][x][y] = dp[z-1][x][y] + dp[z-1][x-1][y] + dp[z-1][x][y-1] - dp[z-1][x-1][y-1]; } //visit是全局变量 //如果已经计算过,则设置标记 visit[z][x][y] = true; } } } return dp[a][b][c]; } //************************main函数**************************** int main() { freopen( "in.txt", "r", stdin ); memset( dp, 0, sizeof(dp) ); memset( visit, false, sizeof(visit) ); int a, b, c; while( cin >> a >> b >> c, !( a == -1 && b == -1 && c == -1 ) ) { int ans = RecSolve( a, b, c ); cout << "w(" << a << ", " << b << ", " << c << ") = " << ans << endl; } return 0; }