ACM学习历程——HDU1331 Function Run Fun(锻炼多维dp的打表)

Description

We all love recursion! Don‘t we?       
Consider a three-parameter recursive function w(a, b, c):       
if a <= 0 or b <= 0 or c <= 0, then w(a, b, c) returns:        1
if a > 20 or b > 20 or c > 20, then w(a, b, c) returns:        w(20, 20, 20)       
if a < b and b < c, then w(a, b, c) returns:        w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c)       
otherwise it returns:        w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1)       
This is an easy function to implement. The problem is, if implemented directly, for moderate values of a, b and c (for example, a = 15, b = 15, c = 15), the program takes hours to run because of the massive recursion.

Input

The input for your program will be a series of integer triples, one per line, until the end-of-file flag of -1 -1 -1. Using the above technique, you are to calculate w(a, b, c) efficiently and print the result.

Output

Print the value for w(a,b,c) for each triple.

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

递推的式子是直接给出来的。里面最关键的两个式子是:

f[i][j][k] = f[i][j][k-1] + f[i][j-1][k-1] - f[i][j-1][k];
以及

f[i][j][k] = f[i-1][j][k] + f[i-1][j-1][k] + f[i-1][j][k-1] - f[i-1][j-1][k-1];

可知这个三维dp式子,前一个式子都是在i那一维,通过特征观察可知,是j一层一层递推的(或者k)。

而第二个式子又可以看出是i一层层的递推。

故递推的时候只需要三个for循环就搞定。

但是还需要注意的是

任意i,j,f[i][j][0] = f[i][0][j] = f[0][i][j] = 1;
这个条件给每一维的0这个面都赋成了1,有了这个初始化,就可以放心地递推了。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <string>
#define inf 0x3fffffff
#define eps 1e-10

using namespace std;

int f[25][25][25];

void Init()
{
    for (int i = 0; i <= 20; i++)
        for (int j = 0; j <= 20; j++)
            f[i][j][0] = f[i][0][j] = f[0][i][j] = 1;
    for (int i = 1; i <= 20; i++)
        for (int j = 1; j <= 20; j++)
            for (int k = 1; k <= 20; k++)
            {
                if (i < j && j < k)
                    f[i][j][k] = f[i][j][k-1] + f[i][j-1][k-1] - f[i][j-1][k];
                else
                    f[i][j][k] = f[i-1][j][k] + f[i-1][j-1][k] + f[i-1][j][k-1] - f[i-1][j-1][k-1];
            }
}

int w(int a, int b, int c)
{
    if (a <= 0 || b <= 0 || c <= 0)
        return 1;
    if (a > 20 || b > 20 || c > 20)
        return f[20][20][20];
    return f[a][b][c];
}

int main()
{
    //freopen("test.txt", "r", stdin);
    Init();
    int a, b, c;
    while (scanf("%d%d%d", &a, &b, &c) != EOF)
    {
        if (a == -1 && b == -1 && c == -1)
            break;
        printf("w(%d, %d, %d) = ", a, b, c);
        printf("%d\n", w(a, b, c));
    }
    return 0;
}
时间: 2024-10-20 14:08:56

ACM学习历程——HDU1331 Function Run Fun(锻炼多维dp的打表)的相关文章

ACM学习历程—CodeForces 176B Word Cut(字符串匹配 &amp;&amp; dp &amp;&amp; 递推)

Description Let's consider one interesting word game. In this game you should transform one word into another through special operations. Let's say we have word w, let's split this word into two non-empty parts x and y so, that w = xy. A split operat

ACM学习历程—HDU 4726 Kia&#39;s Calculation( 贪心&amp;&amp;计数排序)

DescriptionDoctor Ghee is teaching Kia how to calculate the sum of two integers. But Kia is so careless and alway forget to carry a number when the sum of two digits exceeds 9. For example, when she calculates 4567+5789, she will get 9246, and for 12

ACM学习历程—HDU 5023 A Corrupt Mayor&#39;s Performance Art(广州赛区网赛)(线段树)

Problem Description Corrupt governors always find ways to get dirty money. Paint something, then sell the worthless painting at a high price to someone who wants to bribe him/her on an auction, this seemed a safe way for mayor X to make money. Becaus

ACM学习历程—UESTC 1226 Huatuo&#39;s Medicine(数学)(2015CCPC L)

题目链接:http://acm.uestc.edu.cn/#/problem/show/1226 题目就是构造一个对称的串,除了中间的那个只有1个,其余的两边都是对称的两个,自然答案就是2*n-1. 代码: #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #

ACM学习历程—BestCoder Round #75

1001:King's Cake(数论) http://acm.hdu.edu.cn/showproblem.php?pid=5640 这题有点辗转相除的意思.基本没有什么坑点. 代码: #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #include &l

ACM学习历程—HDU5585 Numbers(数论 || 大数)(BestCoder Round #64 (div.2) 1001)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5585 题目大意就是求大数是否能被2,3,5整除. 我直接上了Java大数,不过可以对末尾来判断2和5,对所有位的和来判断3. 代码就不粘了.

ACM学习历程—HDU5587 Array(数学 &amp;&amp; 二分 &amp;&amp; 记忆化 || 数位DP)(BestCoder Round #64 (div.2) 1003)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5587 题目大意就是初始有一个1,然后每次操作都是先在序列后面添加一个0,然后把原序列添加到0后面,然后从0到末尾,每一个都加上1. 例如:a0, a1, a2 => a0, a1, a2, 1, a0+1, a1+1, a2+1 题解中是这么说的:“ 其实Ai为i二进制中1的个数.每次变化A{k+2^i}=A{k}+1,(k<2^?i??)不产生进位,二进制1的个数加1.然后数位dp统计前m个数二

ACM学习历程—HDU 3915 Game(Nim博弈 &amp;&amp; xor高斯消元)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3915 题目大意是给了n个堆,然后去掉一些堆,使得先手变成必败局势. 首先这是个Nim博弈,必败局势是所有xor和为0. 那么自然变成了n个数里面取出一些数,使得xor和为0,求取法数. 首先由xor高斯消元得到一组向量基,但是这些向量基是无法表示0的. 所以要表示0,必须有若干0来表示,所以n-row就是消元结束后0的个数,那么2^(n-row)就是能组成0的种数. 对n==row特判一下. 代码:

ACM学习历程—HDU 5534 Partial Tree(动态规划)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5534 题目大意是给了n个结点,让后让构成一个树,假设每个节点的度为r1, r2, ...rn,求f(x1)+f(x2)+...+f(xn)的最大值. 首先由于是树,所以有n-1条边,然后每条边连接两个节点,所以总的度数应该为2(n-1). 此外每个结点至少应该有一个度. 所以r1+r2+...rn = 2n-2.ri >= 1; 首先想到让ri >= 1这个条件消失: 令xi = ri,则x1+x