zoukankan      html  css  js  c++  java
  • 超简单的记忆化搜索原理以及在做题中出现的错误

    我们经常会做一些递归的题型,在数据规模较小的情况下,不断的调用是可以的但是当数据规模太大时就会出现mte,wa等问题。例如经典例题Function。

    Function:

    题目描述

    对于一个递归函数w(a,b,c)

    如果a<=0 or b<=0 or c<=0就返回值1.

    如果a>20 or b>20 or c>20就返回w(20,20,20)

    如果a<b并且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均为15时,调用的次数将非常的多。你要想个办法才行.

    /*

    absi2011 : 比如 w(30,-1,0)既满足条件1又满足条件2

    这种时候我们就按最上面的条件来算

    所以答案为1

    */

    输入输出格式

    输入格式:

     

    会有若干行.

    并以-1,-1,-1结束.

    保证输入的数在-9223372036854775808~9223372036854775807之间

    并且是整数

     

    输出格式:

     

    输出若干行

    格式:

    [b]w(a,_b,c)=_你的输出(_代表空格)[/b]

     

    输入输出样例

    输入样例#1:
    1 1 1
    2 2 2
    -1 -1 -1
    输出样例#1:
    w(1, 1, 1) = 2
    w(2, 2, 2) = 4

     

     

     

    说明

    记忆化搜索

    没错一道特别水的题但是却是记忆化搜索的本质所在。

    首先分析题:叽里咕噜叽里咕噜…………………………

    定义一个数组book[21][21][21]作为记忆化中储存搜索的,避免再一次算而导致时间,空间上的不足。然后就按照题意来写递归函数。特别注意if语句中的条件。首先是a,b,c的取值范围超过怎么样处理。然后第三个如果记忆数组等于零。也就是说记忆数组并没有被计算到,那么就要直接递归计算。这三个if都没实现就是记忆数组不为零,也就是说当计算到这一步的时候,此次递归被计算过一次。所以说直接返回计算结果。减少再次计算的时间和空间。有许多人会说一个问题:我感觉在写代码的时候,这一个数组应该放在一个等号的右面。就像说i=book[a][b][c]然后用i来进行计算。其实不是这样的,因为在第三个if中说如果记忆数组为零。那么就会进行递归计算。简单的说就是在一开始的时候必须要经过第三个if进行递归计算。。具体的实现过程就看代码吧。注意细节找找第二份代码的错误。

    #include<iostream>

    int book[21][21][21];

    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 w(20,20,20);

        if(!book[a][b][c])

    {

            if(a<b&&b<c)    

    book[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);

            else    

    book[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);

        }

        return book[a][b][c];

    }

    int main(){

        int a,b,c;

        while(1){

            cin>>a>>b>>c;

            if(a==-1&&b==-1&&c==-1) break;

            cout<<"w( "<<a<<", "<<b<<", "<<c<<") = "<<w(a,b,c)<<endl;

        }

        return 0;

    }

    码2:

    #include<iostream> #include<cstdio> using namespace std; int w(int,int,int); int w1[21][21][21]; int a,b,c; int main() { while(1){ cin>>a>>b>>c; if(a==-1&&b==-1&&c==-1) break; printf("w(%d, %d, %d) = %d ",a,b,c,w(a,b,c)); } return 0; } int w(int x,int y,int z) { if(x<=0 || y<=0 || z<=0) return 1; if(x>20 || y>20 || z>20) return w(20,20,20); if(!w1[x][y][z]) { if(x<y && y<z) { w1[x][y][z]=w(x,y,z-1)+w(x,y-1,z-1)-w(x,y-1,z); } else { w1[x][y][z]=w(x-1,y,z)+w(x-1,y-1,z)+w(x-1,y,z-1)-w(x-1,y-1,c-1); } } return w1[x][y][z]; }

    这份代码写了之过了大约10遍,就过了一个数据点。(ps:在数据特别弱的题库做的)第一、第四说是mtl。

    第二、第五说是wa。调了大约一小时。找到结果了:那就是,

    倒数5行。-w(x-1……c-1)打错了,应该打成-w(x-1……z-1)。T_T哎。后悔当时写的时候太匆忙了!!!!!!!!!!!!

    哎,注意细节!!!

    (我的语言表达能力有限-_-!!!)

  • 相关阅读:
    正则表达式
    前端开发工程师
    前端开发工程师
    Java开发工程师(Web方向)
    Java开发工程师(Web方向)
    Java开发工程师(Web方向)
    Java开发工程师(Web方向)
    Java开发工程师(Web方向)
    前端开发工程师
    前端开发工程师
  • 原文地址:https://www.cnblogs.com/srpihot/p/6305491.html
Copyright © 2011-2022 走看看