状态定义:
dp[i][j][result=0/1]表示第i到j个数字计算结果为result的方案数。
状态转移:
枚举区间分割点,根据分割点的情况讨论左右区间计算结果,方案数增量为左右方案数相乘。
分割点为 '&':
结果为0 有三种情况: 0 0, 0 1, 1 0
dp[i][j][0] += dp[i][k - 1][0] * dp[k + 1][j][0] + dp[i][k - 1][0] * dp[k + 1][j][1] + dp[i][k - 1][1] * dp[k + 1][j][0];
结果为1 有一种情况: 1 1
dp[i][j][1] += dp[i][k - 1][1] * dp[k + 1][j][1];
分割点为 '|':
结果为0 有一种情况: 0 0
dp[i][j][0] += dp[i][k - 1][0] * dp[k + 1][j][0];
结果为1 有三种情况: 0 1, 1 0, 1 1
dp[i][j][1] += dp[i][k - 1][0] * dp[k + 1][j][1] + dp[i][k - 1][1] * dp[k + 1][j][0] + dp[i][k - 1][1] * dp[k + 1][j][1];
分割点为 '^':
结果为0 有两种情况: 0 0, 1 1
dp[i][j][0] += dp[i][k - 1][0] * dp[k + 1][j][0] + dp[i][k - 1][1] * dp[k + 1][j][1];
结果为1 有两种情况: 0 1, 1 0
dp[i][j][1] += dp[i][k - 1][1] * dp[k + 1][j][0] + dp[i][k - 1][0] * dp[k + 1][j][1];
class Solution {
public:
int countEval(string s, int result) {
int n=s.size();
vector<vector<vector<int>>>dp(n,vector<vector<int>>(n,vector<int>(2,0)));
for(int i=0;i<n;i+=2){
int temp=0;
if(s[i]=='1')temp=1;
dp[i][i][1]=temp;
dp[i][i][0]=1-temp;
}
//step是块长度减1
//step = 0:每个数字本身
//step = 2:类似1&1
//step = 4:类似1&1&1 以此类推...
for(int step=0;step<n;step+=2){
for(int i=0;i+step<n;i+=2){
for(int j=i+1;j-i<step;j+=2){
int Left0=dp[i][j-1][0],Left1=dp[i][j-1][1];
int Right0=dp[j+1][i+step][0],Right1=dp[j+1][i+step][1];
if(s[j]=='&'){
dp[i][i+step][0]+=Left0*(Right0+Right1)+Left1*Right0;
dp[i][i+step][1]+=Left1*Right1;
}
else if(s[j]=='|'){
dp[i][i+step][0]+=Left0*Right0;
dp[i][i+step][1]+=Left0*Right1+Left1*(Right0+Right1);
}
else{
dp[i][i+step][0]+=Left1*Right1+Left0*Right0;
dp[i][i+step][1]+=Left0*Right1+Left1*Right0;//第一遍写的时候异或搞错了
}
}
}
}
return dp[0][n-1][result];
}
};