careercup-递归和动态规划 9.11

简介: 9.11 给定一个布尔表达式,由0、1、&、|和^等符号组成,以及一个想要的布尔结果result,实现一个函数,算出有几种括号的放法可使该表达式得出result值。 解法: 跟其他递归问题一样,此题的关键在于找出问题与子问题之间的关系。

9.11 给定一个布尔表达式,由0、1、&、|和^等符号组成,以及一个想要的布尔结果result,实现一个函数,算出有几种括号的放法可使该表达式得出result值。

解法:

跟其他递归问题一样,此题的关键在于找出问题与子问题之间的关系。

假设函数int f(expression,result)会返回所有值为return的有效表达式的数量。我们想要算出f(1^0|0|1,true)(也即,给表达式1^0|0|1加括号使其求值为true的所有方式)。每个加括号的表达式最外层肯定有一对括号。因此,我们可以这么做:

也就是说,我们可以迭代整个表达式,将每个运算符当作第一个要加括号的运算符。

现在,又该如何计算这些内层的表达式呢,比如f((1^0)|(0|1),true)?很简单,要让这个表达式的值为true,左半部分和右半部分必有一位true。因此,这个表达式分解如下:

f((1^0) | (0|1),true)= f(1^0,true)* f(0|1,true) +

            f(1^0,false)* f(0|1,true)+

            f(1^0,true) * f(0|1,false)

对每个布尔表达式,都可以进行类似的分解:

对false结果,我们也可以执行非常类似的操作:

至此,要解决这个问题,只需反复套用这些递归关系即可。

C++实现代码:

#include<iostream>
#include<string>
using namespace std;

int f(string exp,bool result,int s,int e)
{
    if(s==e)
    {
        if(exp[s]=='1'&&result)
            return 1;
        else if(exp[s]=='0'&&!result)
            return 1;
        else
            return 0;
    }
    int c=0;
    int i;
    if(result)
    {
        for(i=s+1; i<=e; i+=2)
        {
            if(exp[i-1]=='&')
            {
                c+=f(exp,true,s,i-1)*f(exp,true,i+1,e);
            }
            else if(exp[i]=='|')
            {
                c+=f(exp,true,s,i-1)*f(exp,false,i+1,e);
                c+=f(exp,false,s,i-1)*f(exp,true,i+1,e);
                c+=f(exp,true,s,i-1)*f(exp,true,i+1,e);
            }
            else if(exp[i]=='^')
            {
                c+=f(exp,true,s,i-1)*f(exp,false,i+1,e);
                c+=f(exp,false,s,i-1)*f(exp,true,i+1,e);
            }
        }
    }
    else
    {
        for(i=s+1;i<=e;i+=2)
        {
            if(exp[i-1]=='&')
            {
                c+=f(exp,true,s,i-1)*f(exp,false,i+1,e);
                c+=f(exp,false,s,i-1)*f(exp,true,i+1,e);
                c+=f(exp,false,s,i-1)*f(exp,false,i+1,e);
            }
            else if(exp[i]=='|')
            {
                c+=f(exp,false,s,i-1)*f(exp,false,i+1,e);
            }
            else if(exp[i]=='^')
            {
                c+=f(exp,true,s,i-1)*f(exp,true,i+1,e);
                c+=f(exp,false,s,i-1)*f(exp,false,i+1,e);
            }
        }
    }
    return c;
}

int main()
{
    string str="1^0|0&1&0|1^1^0|1|1&0&1^0|0&1&0|1^1^0|1|1&0^1^0|0&1&0|1^1^0|1|1&0^1^0|0&1&0|1^1^0|1|1&0|1|0|0";
    cout<<f(str,true,0,4)<<endl;
}

虽然这么做可行,但不是很有效,对于同一个exp的值,他会重复算f(exp)很多次。

要解决这个问题,我们可以运用动态规划,缓存不同表达式的结果。注意,我们需要根据expression和result进行缓存。

dp C++实现代码:

#include<iostream>
#include<string>
#include<map>
using namespace std;

int f(string exp,bool result,int s,int e,map<string,int> &mp)
{
    string key=""+result+s+e;
    if(mp.find(key)!=mp.end())
        return mp[key];
    if(s==e)
    {
        if(exp[s]=='1'&&result)
            return 1;
        else if(exp[s]=='0'&&!result)
            return 1;
        else
            return 0;
    }
    int c=0;
    int i;
    if(result)
    {
        for(i=s+1; i<=e; i+=2)
        {
            if(exp[i-1]=='&')
            {
                c+=f(exp,true,s,i-1,mp)*f(exp,true,i+1,e,mp);
            }
            else if(exp[i]=='|')
            {
                c+=f(exp,true,s,i-1,mp)*f(exp,false,i+1,e,mp);
                c+=f(exp,false,s,i-1,mp)*f(exp,true,i+1,e,mp);
                c+=f(exp,true,s,i-1,mp)*f(exp,true,i+1,e,mp);
            }
            else if(exp[i]=='^')
            {
                c+=f(exp,true,s,i-1,mp)*f(exp,false,i+1,e,mp);
                c+=f(exp,false,s,i-1,mp)*f(exp,true,i+1,e,mp);
            }
        }
    }
    else
    {
        for(i=s+1;i<=e;i+=2)
        {
            if(exp[i-1]=='&')
            {
                c+=f(exp,true,s,i-1,mp)*f(exp,false,i+1,e,mp);
                c+=f(exp,false,s,i-1,mp)*f(exp,true,i+1,e,mp);
                c+=f(exp,false,s,i-1,mp)*f(exp,false,i+1,e,mp);
            }
            else if(exp[i]=='|')
            {
                c+=f(exp,false,s,i-1,mp)*f(exp,false,i+1,e,mp);
            }
            else if(exp[i]=='^')
            {
                c+=f(exp,true,s,i-1,mp)*f(exp,true,i+1,e,mp);
                c+=f(exp,false,s,i-1,mp)*f(exp,false,i+1,e,mp);
            }
        }
    }
    mp[key]=c;
    return c;
}

int fDP(string exp,bool result,int s,int e)
{
    map<string,int> dp;
    return f(exp,result,s,e,dp);
}
int main()
{
    string str="1^0|0&1&0|1^1^0|1|1&0&1^0|0&1&0|1^1^0|1|1&0^1^0|0&1&0|1^1^0|1|1&0^1^0|0&1&0|1^1^0|1|1&0|1|0|0";
    cout<<fDP(str,true,0,4)<<endl;
}

 

相关文章
素因子分解(递归求解)
素因子分解(递归求解)
133 0
|
6月前
|
存储 算法 数据可视化
LeetCode 题目 97:动态规划、递归到广度优先搜索BFS 实现交错字符串
LeetCode 题目 97:动态规划、递归到广度优先搜索BFS 实现交错字符串
|
7月前
|
搜索推荐 算法 C++
【递归版】归并排序算法(1)
【递归版】归并排序算法(1)
56 0
C#中汉诺塔问题的递归解法
百度测试部2015年10月份的面试题之——汉诺塔。 汉诺塔就是将一摞盘子从一个塔转移到另一个塔的游戏,中间有一个用来过度盘子的辅助塔。 百度百科在此。 游戏试玩在此。 用递归的思想解决汉诺塔问题就是分为两种情况: 第一种情况是只有一个盘子的情况,也就是最基本的情况,这种情况下,直接将该盘子从原始塔转移到目标塔即可胜利; 第二种情况是右n个盘子的情况,也就是普遍情况,这种情况下,要将除了最底下的那个盘子以外的(n-1)个盘子从原始塔转移到辅助塔,再把最底下的那个盘子(第n个盘子)从原始塔转移到目标塔,最后将辅助塔的(n-1)个盘子从辅助塔转移到目标塔。
1847 0
|
机器学习/深度学习 缓存 机器人
从暴力递归到动态规划,记忆化搜索
从暴力递归到动态规划,记忆化搜索
从暴力递归到动态规划,记忆化搜索
循环、递归、分治、回溯、动态规划
循环、递归、分治、回溯、动态规划
128 0
动态规划练习——从暴力递归—>记忆化搜索—>经典动态规划
动态规划练习——从暴力递归—>记忆化搜索—>经典动态规划
|
机器学习/深度学习 算法
一文学会递归解题 | 算法必看系列四
递归是算法中一种非常重要的思想,应用也很广,小到阶乘,再在工作中用到的比如统计文件夹大小,大到 Google 的 PageRank 算法都能看到,也是面试官很喜欢的考点。
一文学会递归解题 | 算法必看系列四
递归与动态规划
凡是递归的过程,都可以化成树的过程。递归就是问题变成子问题求解的过程。动态规划暂时没明白,好像是需要一张动态规划表,是根据递归搞出来的。 问题1:开始有一头母牛,母牛每年会生一只母牛,新出生的母牛成长三年后也能每年生一只母牛,假设牛都不会死。
697 0
careercup-递归和动态规划 9.10
9.10 给你一堆n个箱子,箱子宽w,高h,深d。箱子不能翻转,将箱子堆起来时,下面箱子的宽度、高度和深度必须大于上面的箱子。实现一个方法,搭出最高的一堆箱子,箱堆的高度为每个箱子高度的总和。 解法: 要解决此题,我们需要找到不同子问题之间的关系。
794 0