1、问题描述:来源《算法与数据结构最优解》左程云著
给定一个只由0(假)、1(真)、&(逻辑与)、|(逻辑或)、^(异或)五种字符组成的字符串express,再给定一个布尔值desired。返回express能有多少种组合方式,可以达到desired的结果。
2、输入输出
express="1^0|0|1",desired=false。只有1^((0|0)|1)和1^(0|(0|1))的组合可以得到false,返回2。
express="1",desired=false。没有组合可以得到false,返回0.
输入错误输出-1
3、问题解析
1)这个问题是一个“加括号”问题,和矩阵连乘的计算过程类似,但是要比后者复杂很多。
2)问题的难点在于找出“状态”和“递推式”,因为状态不是唯一的,是和输入的desired有关系。
3)但是我们可以确定的是,只有两种状态,那就是表达式为真的数目和表达式为假的数目,令t[i][j]为从 i 到 j 表达式为真的数目,f[i][j]为表达式为假的数目。
4)初始状态:i==j,如果express[j]==1,那么t[j][j]=1;f[j][j]=0;如果express[j]==0,t[j][j]=0;f[j][j]=1。
递推状态:i!=j,t[i][j]和f[i][j]的计算之间有依赖的关系,而且和具体的运算符也有关系,拿“|”(或运算)来举例,真=真*真+真*假+假*真,假=假*假(或运算法则),也就是t[i][j]=t[i][k]*t[k+2][j]+t[i][k]*f[k+2][j]+f[i][j]*t[k+2][j],其中i<=k<j,k+=2。
5)这个题目的思路和纸牌博弈问题类似,都是两个状态,而且互相对立,互相依赖。
4、代码如下
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int getResult(string, string);
int main() {
string str,desired;
cin >> str >> desired;
cout << getResult(str, desired) << endl;
}
int getResult(string str, string desired) {
int len = str.length();
//判断字符串是否有效
if (len % 2 == 0)
return -1;
int i, j, k;
vector<vector<int>> t(len, vector<int>(len)), f(len, vector<int>(len));//t[i][j]代表从str[i]到str[j]值为true的个数,f[i][j]代表为false的数目
for (j = 0; j < len; j += 2) {
if (str[j] == '1') {
t[j][j] = 1;
f[j][j] = 0;
}
else if (str[j] == '0') {
t[j][j] = 0;
f[j][j] = 1;
}
else return -1;
cout << j << "行 " << j << "列 真:" << t[j][j] << " 假: " << f[j][j] << endl;
for (i = j - 2; i >= 0; i -= 2) {//计算的顺序是先计算列,再从下向上
for (k = i; k < j; k += 2) {//k从i遍历到j,类似于矩阵连乘,这个是一个累加
//cout << "K的值:" << k << endl;
switch (str[k + 1]) {
case '|':t[i][j] += t[i][k] * (t[k + 2][j] + f[k + 2][j]) + f[i][k] * t[k + 2][j];
f[i][j] += f[i][k] * f[k + 2][j];
break;//如果是或,那么只要两边有任意一个真,那么结果就是真;用乘法的原因是假设左边有m种组合,右边有n种组合,那么总的组合方案数目就是m*n种
case '&':t[i][j] += t[i][k] * t[k + 2][j];
f[i][j] += f[i][k] * (t[k + 2][j] + f[k + 2][j]) + t[i][k] * f[k + 2][j];
break;
case '^':t[i][j] += t[i][k] * f[k + 2][j] + f[i][k] * t[k + 2][j];
f[i][j] += t[i][k] * t[k + 2][j] + f[i][k] * f[k + 2][j];
break;
default: return -1;
}
}//end for k
cout << i << "行 " << j << "列 真:" << t[i][j] << " 假: " << f[i][j] << endl;
}//end for i
}//end for j
return desired == "false" ? f[0][len - 1] : t[0][len - 1];
}