#include #include #include #include #include using namespace std; /* 问题:给定一个布尔表达式,由0、1、&、|和^等符号组成,以及一个想要的布尔结果result,实现一个函数,算出有几种括号的方法可使该 表达式得出result值。 分析:书上解法,采用以符号作为分割,符号左边和符号右边分别加表达式的方式进行计算。 比如表达式为: 1^0|0|1, 以第一个符号"^"拆分为 1^(0|0|1) 二 (1^0)|(0|1) .... 最关键的就是进行表达式等价转换:假设表达式为exp,拆分为左右表达式我exp1,exp2, 设f(exp1|exp2 , result)为表达式f(exp,result)是表达式exp符合result的结果集个数 当result=true时, 与运算为true,则exp1和exp2必须都为true f(exp1 & exp2 , true) = f(exp1 ,true) * f(exp2 , true) 【1】 或运算为true,分三种情况:两个都为true,exp1为true且exp2为false,exp1为false且exp2位true f(exp1 | exp2 , true) = f(exp1 , true) * f(exp2,true)+f(exp1, true)*f(exp2,false)+f(exp1,false)*f(exp2,true)【2】 异或运算为true,必定一个为true,一个为false f(exp1 ^ exp2 , true) = f(exp1,true)*f(exp2,false) + f(exp1,false)*f(exp2,true)【3】 当result为false时, 与运算为false,两个都为false,或者其中一个为false,一个为true f(exp1 & exp2 , false)=f(exp1 , false) * f(exp2,false)+f(exp1, false)*f(exp2,true)+f(exp1,true)*f(exp2,false) 【4】 或运算为false,两个都为flase f(exp1 | exp2 , false) = f(exp1,false)*f(exp2,false) 【5】 异或运算为flase,两个同为true或同为flase f(exp1 ^ exp2, false) = f(exp1,true)*f(exp2,true) + f(exp1,false)*f(exp2,false)【6】 采用上述方式递归将表达式拆分,根据result的值,分别采用上述公式【1】~公式【6】进行处理即可 发现在程序员面试金典中,所谓的动态规划变成了=记忆化搜索+递归,这其实不是动态规划,而是递归 这里递归的本质就是通过符号来将表达式一分为2,对每部分表达式再递归计算 输入:输入第一个字符串为表达式,第二个字符串为表达式的值 1^0|0|1 true 输出:输出通过给表达式括号,可以使得表达式的值为给定布尔值的方法个数 3 关键: 1 比如表达式为: 1^0|0|1, 以第一个符号"^"拆分为 1^(0|0|1) 二 (1^0)|(0|1) .... 最关键的就是进行表达式等价转换:假设表达式为exp,拆分为左右表达式我exp1,exp2, 设f(exp1|exp2 , result)为表达式f(exp,result)是表达式exp符合result的结果集个数 当result=true时, 与运算为true,则exp1和exp2必须都为true f(exp1 & exp2 , true) = f(exp1 ,true) * f(exp2 , true) 【1】 或运算为true,分三种情况:两个都为true,exp1为true且exp2为false,exp1为false且exp2位true f(exp1 | exp2 , true) = f(exp1 , true) * f(exp2,true)+f(exp1, true)*f(exp2,false)+f(exp1,false)*f(exp2,true)【2】 异或运算为true,必定一个为true,一个为false f(exp1 ^ exp2 , true) = f(exp1,true)*f(exp2,false) + f(exp1,false)*f(exp2,true)【3】 当result为false时, 与运算为false,两个都为false,或者其中一个为false,一个为true f(exp1 & exp2 , false)=f(exp1 , false) * f(exp2,false)+f(exp1, false)*f(exp2,true)+f(exp1,true)*f(exp2,false) 【4】 或运算为false,两个都为flase f(exp1 | exp2 , false) = f(exp1,false)*f(exp2,false) 【5】 异或运算为flase,两个同为true或同为flase f(exp1 ^ exp2, false) = f(exp1,true)*f(exp2,true) + f(exp1,false)*f(exp2,false)【6】 采用上述方式递归将表达式拆分,根据result的值,分别采用上述公式【1】~公式【6】进行处理即可 发现在程序员面试金典中,所谓的动态规划变成了=记忆化搜索+递归,这其实不是动态规划,而是递归 这里递归的本质就是通过符号来将表达式一分为2,对每部分表达式再递归计算 2 //如果当前只有一个字符,容易遗漏 if(s == e) { if( '1' == exp.at(s) && result) { return 1; } else if('0' == exp.at(s) && !result) { return 1; } return 0; } */ //计算表达式exp中从下标s到e的表达式中通过加括号符合result的摆放个数 int f(string& exp , bool result , int s , int e , map& expToTimes) { //鲁棒性 if(exp.empty() || s < 0 || e < 0 ) { return 0; } //如果之前已经计算过了:字符串起始位置处下为result的次数,就直接返回 stringstream ss; ss << result << " " << s << " " << e; string key = ss.str(); if(expToTimes.find(key) != expToTimes.end()) { return expToTimes.find(key)->second; } //如果当前只有一个字符,容易遗漏 if(s == e) { if( '1' == exp.at(s) && result) { return 1; } else if('0' == exp.at(s) && !result) { return 1; } return 0; } //下面对表达式进行拆分,s对应了字符,s+1对应符号,所以每次间隔2个字符做递归处理 int count = 0; for(int i = s + 1 ; i <= e ; i += 2) { if(result) { switch( exp.at(i) ) { case '&': count += f(exp , true , s , i-1 ,expToTimes) * f(exp , true , i+1 , e,expToTimes); break; case '|': count += f(exp , true , s , i-1,expToTimes) * f(exp,true , i+1 , e,expToTimes) + f(exp, true , s , i-1,expToTimes)*f(exp,false, i+1 , e,expToTimes) + f(exp,false , s , i -1 ,expToTimes) * f(exp,true , i+1 , e,expToTimes); break; case '^': count += f(exp,true , s , i-1,expToTimes)*f(exp,false,i+1 , e ,expToTimes) + f(exp,false, s , i-1,expToTimes)*f(exp,true,i+1 , e,expToTimes); break; default: break; } } else { switch( exp.at(i)) { case '&': count += f(exp , false , s , i-1,expToTimes) * f(exp,false,i+1,e,expToTimes) + f(exp, false, s , i-1,expToTimes)*f(exp,true,i+1,e,expToTimes) + f(exp,true, s , i-1,expToTimes)*f(exp,false,i+1,e,expToTimes); break; case '|': count += f(exp,false, s , i-1,expToTimes)*f(exp,false,i+1,e,expToTimes); break; case '^': count += f(exp,true, s , i-1,expToTimes)*f(exp,true,i+1,e,expToTimes) + f(exp,false, s , i-1,expToTimes)*f(exp,false,i+1,e,expToTimes); break; default: break; } } } expToTimes.insert(pair(key , count)); return count; } void process() { string exp , result; bool bResult; map expToTimes; while(cin >> exp >> result) { expToTimes.clear(); if("true" == result) { bResult = true; } else if("false" == result) { bResult = false; } else { cout << "Input is wrong , please input again!" << endl; continue; } //接下来计算 int result = f(exp , bResult , 0 , exp.size() - 1 , expToTimes); cout << result << endl; } } int main(int argc, char* argv[]) { process(); getchar(); return 0; }