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]==''&&result)
return ;
else if(exp[s]==''&&!result)
return ;
else
return ;
}
int c=;
int i;
if(result)
{
for(i=s+; i<=e; i+=)
{
if(exp[i-]=='&')
{
c+=f(exp,true,s,i-)*f(exp,true,i+,e);
}
else if(exp[i]=='|')
{
c+=f(exp,true,s,i-)*f(exp,false,i+,e);
c+=f(exp,false,s,i-)*f(exp,true,i+,e);
c+=f(exp,true,s,i-)*f(exp,true,i+,e);
}
else if(exp[i]=='^')
{
c+=f(exp,true,s,i-)*f(exp,false,i+,e);
c+=f(exp,false,s,i-)*f(exp,true,i+,e);
}
}
}
else
{
for(i=s+;i<=e;i+=)
{
if(exp[i-]=='&')
{
c+=f(exp,true,s,i-)*f(exp,false,i+,e);
c+=f(exp,false,s,i-)*f(exp,true,i+,e);
c+=f(exp,false,s,i-)*f(exp,false,i+,e);
}
else if(exp[i]=='|')
{
c+=f(exp,false,s,i-)*f(exp,false,i+,e);
}
else if(exp[i]=='^')
{
c+=f(exp,true,s,i-)*f(exp,true,i+,e);
c+=f(exp,false,s,i-)*f(exp,false,i+,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,,)<<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]==''&&result)
return ;
else if(exp[s]==''&&!result)
return ;
else
return ;
}
int c=;
int i;
if(result)
{
for(i=s+; i<=e; i+=)
{
if(exp[i-]=='&')
{
c+=f(exp,true,s,i-,mp)*f(exp,true,i+,e,mp);
}
else if(exp[i]=='|')
{
c+=f(exp,true,s,i-,mp)*f(exp,false,i+,e,mp);
c+=f(exp,false,s,i-,mp)*f(exp,true,i+,e,mp);
c+=f(exp,true,s,i-,mp)*f(exp,true,i+,e,mp);
}
else if(exp[i]=='^')
{
c+=f(exp,true,s,i-,mp)*f(exp,false,i+,e,mp);
c+=f(exp,false,s,i-,mp)*f(exp,true,i+,e,mp);
}
}
}
else
{
for(i=s+;i<=e;i+=)
{
if(exp[i-]=='&')
{
c+=f(exp,true,s,i-,mp)*f(exp,false,i+,e,mp);
c+=f(exp,false,s,i-,mp)*f(exp,true,i+,e,mp);
c+=f(exp,false,s,i-,mp)*f(exp,false,i+,e,mp);
}
else if(exp[i]=='|')
{
c+=f(exp,false,s,i-,mp)*f(exp,false,i+,e,mp);
}
else if(exp[i]=='^')
{
c+=f(exp,true,s,i-,mp)*f(exp,true,i+,e,mp);
c+=f(exp,false,s,i-,mp)*f(exp,false,i+,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,,)<<endl;
}

careercup-递归和动态规划 9.11的更多相关文章

  1. 《Cracking the Coding Interview》——第9章:递归和动态规划——题目11

    2014-03-21 20:20 题目:给定一个只包含‘0’.‘1’.‘|’.‘&’.‘^’的布尔表达式,和一个期望的结果(0或者1).如果允许你用自由地给这个表达式加括号来控制运算的顺序,问 ...

  2. 70. Climbing Stairs【leetcode】递归,动态规划,java,算法

    You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb ...

  3. 算法 递归 迭代 动态规划 斐波那契数列 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  4. C#递归、动态规划计算斐波那契数列

    //递归         public static long recurFib(int num)         {             if (num < 2)              ...

  5. 面试题目——《CC150》递归与动态规划

    面试题9.1:有个小孩正在上楼梯,楼梯有n个台阶,小孩一次可以上1阶.2阶或者3阶.实现一个方法,计算小孩有多少种上楼梯的方式. 思路:第4个数是前三个数之和 注意:能不能使用递归,能不能建立一个很大 ...

  6. python---通过递归和动态规划策略解决找零钱问题

    也是常见套路. # coding = utf-8 def rec_mc(coin_value_list, change, know_results): min_coins = change if ch ...

  7. Idea 02.暴力递归与动态规划(1)

    1,关键词解释 1.1 暴力递归: 1, 把问题转化为规模缩小了的同类问题的子问题 2, 有明确的不需要继续进行递归的条件(base case) 3, 有当得到了子问题的结果之后的决策过程 4, 不记 ...

  8. scramble-string——两个字符串经过树化并旋转后是否一致、递归、动态规划

    Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrin ...

  9. OptimalSolution(1)--递归和动态规划(2)矩阵的最小路径和与换钱的最少货币数问题

    一.矩阵的最小路径和 1 3 5 9 1 4 9 18 1 4 9 18 8 1 3 4 9 9 5 8 12 5 0 6 1 14 14 5 11 12 8 8 4 0 22 22 13 15 12 ...

随机推荐

  1. 用PersonalRank实现基于图的推荐算法

    今天我们讲一个下怎么使用随机游走算法PersonalRank实现基于图的推荐. 在推荐系统中,用户行为数据可以表示成图的形式,具体来说是二部图.用户的行为数据集由一个个(u,i)二元组组成,表示为用户 ...

  2. 【HDOJ】4057 Rescue the Rabbit

    挺有意思的一道题目,解法是AC自动机+DP.AC自动机建立fail指针时,一定要注意结点的属性也需要传递.AC自动机结合了trie和kmp的优点.需要注意的是,每个模式串仅计算一次,否则这题很难解. ...

  3. WCF - Consuming WCF Service

    WCF services allow other applications to access or consume them. A WCF service can be consumed by ma ...

  4. C#中的几个线程同步对象方法

    在编写多线程程序时无可避免会遇到线程的同步问题.什么是线程的同步呢? 举个例子:如果在一个公司里面有一个变量记录某人T的工资count=100,有两个主管A和B(即工作线程)在早一些时候拿了这个变量的 ...

  5. RMAN综合学习之备份

    rman是最经济实惠的oracle备份工具,在这里做一个rman的整体学习. 文章中大多是rman命令的语法,还是最好做做实验,以便印象深刻,因为大多数数据库的备份就是按时跑脚本,恢复也不是经常能遇到 ...

  6. Apache FileUpload实现文件上传

    今天,我来介绍一个Apache FileUpload这个插件的使用. 首先,到官网下载相关jar包点击这里下载,这里提供是v1.2. 1.在项目中导入相关jar包commons-fileupload- ...

  7. MVC 路由规则

    一.路由规则说明 先来看MVC中的默认路由的说明 "{controller}/{action}/{id}", // URL with parameters 对于Url /Home/ ...

  8. 详解强大的SQL注入工具——SQLMAP

    1. 前言  Windows下的注入工具好的又贵,免费的啊D.明小子等又不好用,我们根本没必要花 时间去找什么破解的havij.pangolin什么的,特别是破解的工具很可能被绑了木马.其实 Linu ...

  9. [转]NHibernate之旅(12):初探延迟加载机制

    本节内容 引入 延迟加载 实例分析 1.一对多关系实例 2.多对多关系实例 结语 引入 通过前面文章的分析,我们知道了如何使用NHibernate,比如CRUD操作.事务.一对多.多对多映射等问题,这 ...

  10. [liu yanling]测试小结

    编写测试用例,业务了解是基础,结合业务编写测试用例,重要的逻辑一定要覆盖