杭电1331 Function Run Fun
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8049 Accepted Submission(s): 3625
Problem Description
我们都喜欢递归!我们不是吗?
考虑一个三参数递归函数w(a,b,c):
如果a<=0或b<=0或c<=0,则w(a,b,c)返回:
1
如果a>20或b>20或c>20,则w(a,b,c)返回:
w(20,20,20)
如果a<b和b<c,则w(a,b,c)返回:
w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,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)
这是一个易于实现的功能。问题是,如果直接实现,对于a、b和c的中等值(例如,a=15,b=15,c=15),由于大量递归,程序运行需要数小时。
Input
程序的输入将是一系列整数三元组,每行一个,直到文件结束标志-1-1-1。使用上述技术,您可以高效地计算w(a,b,c)并打印结果
Output
打印每个三元组的w(a,b,c)值。
Sample Input
1 1 1
2 2 2
10 4 6
50 50 50
-1 7 18
-1 -1 -1
Sample Output
w(1, 1, 1) = 2
w(2, 2, 2) = 4
w(10, 4, 6) = 523
w(50, 50, 50) = 1048576
w(-1, 7, 18) = 1
分析:
这是一道ACM的题目,意味着它可能会超时,总所周知:ACM的时间短的有时甚至容不下三重循环,所以,想要用递归的同学就会发现程序超时,并不能快乐的AC。所以我们采取用空间换时间的方法来缩短运行时间,废话少说,上代码:
using namespace std;
int f[25][25][25];
//有题目可知我们真正需要计算的只有a,b,c,0到20之间的数,
//所以我们先要用蛮力法穷举这8000种情况。
//我们在这里定义一个全局变量的数组,目的是将前20位计算结果进行存储,
//方便后面的输出。
void w(int a, int b, int c)
{
if (a <= 0 || b <= 0 || c <= 0)
{
f[a][b][c] = 1;
//这一步好像和main函数重复了,但这不是冗余,这是为数组赋初值
//否则输出的结果会为0,因为没有为数组赋初值值
}
else if (a < b && b < c)
{
f[a][b][c] =
f[a][b][c - 1] + f[a][b - 1][c - 1] - f[a][b - 1][c];//这些看仔细了,别抄错了。
}
else
{
f[a][b][c] =
f[a - 1][b][c] + f[a - 1][b - 1][c] + f[a - 1][b][c - 1]
- f[a - 1][b - 1][c - 1];
}
}
int main()
{
int a, b, c;
int i, j, k;
for (i = 0; i < 21; i++)
{
for (j = 0; j < 21;j++)
{
for (k = 0; k < 21; k++)
{
w(i, j, k);
//在这里调用w函数,进行穷举
}
}
}
while (cin >> a >> b >> c)
//这个循环的目的就是进行输出
{
if (a == -1 && b == -1 && c == -1)
{
break;
}
if (a <= 0 || b <= 0 || c <= 0)
{
cout << "w(" << a << ", " << b << ", " << c << ") = "
<< 1 << endl;
continue;
}
if (a > 20 || b > 20 || c > 20)
{
cout << "w(" << a << ", " << b << ", " << c << ") = "
<< f[20][20][20] << endl;
continue;
}
cout << "w(" << a << ", " << b << ", " << c << ") = "
<< f[a][b][c] << endl;
}
return 0;
}