POJ 1579(备忘录算法)

Function Run Fun

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 13491   Accepted: 7023

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
 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5
 6 const int N = 100;
 7 int d[N][N][N];
 8 bool vis[N][N][N];
 9
10 //a,b,c可能是负值,而数组下标无负值,需特殊处理
11 int fun(int a,int b,int c)//必须带参数,因为中间需要转存且参数变了
12 {
13    // if(((a<=0||b<=0||c<=0)||(a>20||b>20||c>20)||(a<b&&b<c))&&!vis[a][b][c])//这个条件不对因为若abc其一为负数便执行了else if,需要把第一个条件单独搞出来
14     if((a<=0||b<=0||c<=0)||(((a>20||b>20||c>20)||(a<b&&b<c))&&!vis[a][b][c]))
15     {
16         if(a<=0||b<=0||c<=0)
17             return 1;
18         if(a>20||b>20||c>20&&!vis[a][b][c])
19         {
20             d[a][b][c] = fun(20,20,20);
21             //d[20][20][20] = fun(20,20,20);
22             d[20][20][20] = d[a][b][c];
23             vis[a][b][c] = 1;
24             vis[20][20][20] = 1;
25         }
26         if(a<b&&b<c&&!vis[a][b][c])
27         {
28             d[a][b][c-1] = fun(a,b,c-1);
29             vis[a][b][c-1] = 1;
30             d[a][b-1][c-1] = fun(a,b-1,c-1);
31             vis[a][b-1][c-1] = 1;
32             d[a][b-1][c] = fun(a,b-1,c);
33             vis[a][b-1][c] = 1;
34             d[a][b][c] =d[a][b][c-1] + d[a][b-1][c-1] - d[a][b-1][c];
35             vis[a][b][c] = 1;
36         }
37     }
38     else if(!vis[a][b][c])//加上了if后效率大增
39     {
40         d[a-1][b][c] = fun(a-1, b, c);
41         vis[a-1][b][c] = 1;
42         d[a-1][b-1][c] = fun(a-1, b-1, c);
43         vis[a-1][b-1][c] = 1;
44         d[a-1][b][c-1] = fun(a-1, b, c-1);
45         vis[a-1][b][c-1] = 1;
46         d[a-1][b-1][c-1] = fun(a-1, b-1, c-1);
47         vis[a-1][b-1][c-1] = 1;
48         d[a][b][c] = d[a-1][b][c] + d[a-1][b-1][c] + d[a-1][b][c-1] - d[a-1][b-1][c-1];
49         vis[a][b][c] = 1;
50     }
51     return d[a][b][c];
52 }
53
54 int main()
55 {
56     int i,j,k;
57     int a, b, c;
58     while(cin>>a>>b>>c&&!(a==-1&&b==-1&&c==-1))
59     {
60         memset(d,-1,sizeof(d));
61         memset(vis,0,sizeof(vis));
62         vis[0][0][0] = 1;
63         d[0][0][0] = 1;
64         int ans = fun(a,b,c);
65         //cout<<"w("<<a<<","<<b","<<c<<") = "<<ans<<endl;
66         printf("w(%d, %d, %d) = %d\n",a,b,c,ans);//注意有4个空格,原来只注意到了等号两侧的空格吃了一个PE
67     }
68     return 0;
69 }
70
71         

 

时间: 2024-10-01 19:48:55

POJ 1579(备忘录算法)的相关文章

poj 1125 Floyd算法

一.题目大意 可以说理解题目比解题难~~明显的多源最短路径,我用的Floyd,Floyd也可以算是dp的一种. 题目可能有多组测试数据,每个测试数据的第一行为经纪人数量N(当N=0时,输入数据结束),然后接下来N行描述第i(1<=i<=N)个经纪人与其他经纪人的关系.每行开头数字M为该行对应的经纪人有多少个经纪人朋友(该节点的出度,可以为0),然后紧接着M对整数,每对整数表示成a,b,则表明该经纪人向第a个经纪人传递信息需要b单位时间(即第i号结点到第a号结点的孤长为b),整张图为有向图,即弧

算法题之poj 1961 Period(KMP, 最短循环节)

题目链接: POJ  : http://poj.org/problem?id=1961 HDU : http://acm.hdu.edu.cn/showproblem.php?pid=1358 ZOJ   : http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2177 题目大意: 给定一个长度为n的字符串s,求它的每个前缀的最短循环节.换句话说,对于每个i (2<=i<=n),求一个最大的整数K>1(如果K存在),使

矩阵连乘的算法问题

写给自己的话: 有时候虽然一道题懂做了,但是发现写解题报告时,要清楚把自己的思路描述出来却挺难的.做解题报告 不仅可以巩固.梳理知识,还可以加深理解.现在我还做得很不好, 一定要坚持! 加油! 矩阵链乘问题: 例子: (下面第二个{P1应该是P2) void MatrixChain() { int i, j, k, t; for(i = 1; i <= n; i++) m[i][i] = 0; //对角线赋值为0,是因为1个矩阵需做0次相乘 for(r=2; r<=n; ++r){ for(i

算法:poj 1155 TELE (树形背包dp)

题意 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结 构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点. 从 转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号 的费用总和. 现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪 些用户提供信号而不给哪些用户提供信号. 写一个程序找出一个方案使得有线电视网在不亏本的情况 下使观看转播的用户尽可能多. 思路 树形

算法:poj 2749 &amp;amp; hdu 1815 Building roads(2-SAT + 二分,好题)

[题目大意] 有n个牛棚, 还有两个中转站S1和S2, S1和S2用一条路连接起来. 为了使得任意 牛棚两个都可以有道路联通,现在要让每个牛棚都连接一条路到S1或者S2. 有a对牛棚互相有仇恨, 所以不能让他们的路连接到同一个中转站.还有b对牛棚互相喜欢,所以他们的路必须连到同一个中专站. 道路的长度是两点的曼哈顿距离. 问最小的任意两牛棚间的距离中的最大值是多少? [思路] 两天前看了这题,当时没什么想法,今天又翻看了一下,想出来了. 每个 牛棚有可以选择S1或者S2,并且有矛盾对,是2-SA

算法题:poj 3080 Blue Jeans(KMP匹配,枚举子串)

链接: http://poj.org/problem?id=3080 题目大意: 给出m(2<=m<=10)个DNA序列, 求出这m个序列中最长的公共字串.如果有多个相同长度的, 输出字典序最小的. 分析与总结: 依次枚举所有的子串, 然后再看是否在所有序列中都能够匹配.保存下长度最大且字典序最小的序 列. 代码: #include<iostream> #include<cstdio> #include<cstring> using namespace st

算法题:poj 2541 Binary Witch(KMP水过,逆序转换)

链接: http://poj.org/problem?id=2541 分析与总结: 做这题估算了下复杂度,觉得无论KMP再怎么快,这题暴力也肯定要超时的. 想了很久也没想出个好办法,于是决定暴力之,但是TLE了....于是就放了几天.之后看了下discuss ,这题的正解应该是状态压缩dp,不过目前我还不懂,跪了. 之后百度发现也可以用KMP水过,虽然是因为数据水才过的,不过这种思路很巧妙,值得借鉴! 直接暴力是枚举字符串的后面13个的字母,然后再用KMP匹配,这样的话,就绪要枚举多次,分别是

【POJ 1330 Nearest Common Ancestors】LCA问题 Tarjan算法

题目链接:http://poj.org/problem?id=1330 题意:给定一个n个节点的有根树,以及树中的两个节点u,v,求u,v的最近公共祖先. 数据范围:n [2, 10000] 思路:从树根出发进行后序深度优先遍历,设置vis数组实时记录是否已被访问. 每遍历完一棵子树r,把它并入以r的父节点p为代表元的集合.这时判断p是不是所要求的u, v节点之一,如果r==u,且v已访问过,则lca(u, v)必为v所属集合的代表元.p==v的情况类似. 我的第一道LCA问题的Tarjan算法

编码-poj 2058算法题Word Encoding完整代码

问题描述 poj 2058算法题Word Encoding完整代码 题目描述 In any language, certain combinations of letters do not appear (or at least appear so seldom that they can be considered non-existent). For instance, there are no English words containing the three letter combin