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; }