B | Evaluate the Expression Input: Standard Input Output: Standard Output |
In this problem, we will consider a mathematical expression according to the following BNF grammar:
<expression> = <variable> | <expression><operator><expression>| “(“<expression>“)”
<operator> = “+” | “*”
<variable> = “a” | “b” | “c” | … | “y” | “z”
When evaluating such expressions, you have to follow the conventional rules. That means you have to do things in the brackets first and multiplications have to be done before addition.
Example: 2*(3+4*2) = 22
Given an expression and some inequalities, you have to assign each variable with a positive integer so that the value of the expression is minimized.
Consider an example:
Expression = a+b*c and Inequalities = a>b, c>b
Assignment of: a=2, b=1 and c=2 will give us the minimum value. => 2 + 1*2 = 4
Input
The first line of input is an integer T(T<100) that gives us the number of test cases. Each case starts with a line that gives you the expression. The length of the expression is at most 300. The next line contains an integer I(I<400) that gives you the number of inequalities. Each of the next Ilines will give you an inequality of the format x>y where x and y are lowercase alphabets that are present in the given expression and x is not equal to y. All the inequalities will be distinct.
Output
For each case, output the case number first. Then output the minimum value of the expression that can be obtained by assigning positive integers to each variable that abides by the given inequalities. You can assume the output will fit in 32 bit signed integer. If the inequalities are inconsistent, then output -1 instead.
Sample Input Output for Sample Input
3
| Case 1: 4 Case 2: 9 Case 3: 4
|
Problem Setter: Sohel Hafiz, Special Thanks: Renat Mullakhanov
题目大意:T组测试数据,对于每组测试数据,一个表达式,包含 a 到 z 的变量,以及 + 和 * 运算符,以及 左括号,右括号, 接下俩是 m 组限制条件,求出表达式的结果,要求最小。
解题思路:(1)可以先计算各个变量的值(2)根据表达式求结果。
(1)具体算法:
尽量让每个变量尽可能小,最终(2)的答案就最小,也就是所谓的贪心。
计算变量的值用的是松弛技术,对每个变量初始化赋值为1,接下来 如果 要求 a<b ,但是 实际 a>=b,那么令 a=b+1,这样赋值,反之亦然,一直松弛下去 ,
直到满足条件为止。不满足条件也就是可能存在负环,也就是 a>b,b>a,这就是负环,判断负环的方法就是松弛到一定程度还不能解决,也就是 某个变量的值大于26了
(2)具体算法:
利用编译原理这门课的思想,但是注意优化
这个表达式可以看成为 项,项又有以下三种形式:
一、 项 = (项)
二、项 = 项 + 项
三、项 = 项 * 项
对于 项 = (项) 很简单,对于第二种和第三种,只需枚举加号或乘号的位置,划分子问题,看是否满足条件即可,记得用记忆化dp,否则超时。
解题代码:
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
using namespace std;
string st;
vector <string> v;
int a[30],m,dp[310][310];
void input(){
v.clear();
for(int i=1;i<=26;i++) a[i]=1;
cin>>st>>m;
for(int i=0;i<m;i++){
string tmp;
cin>>tmp;
v.push_back(tmp);
}
for(int i=0;i<=st.length();i++)
for(int j=0;j<=st.length();j++)
dp[i][j]=-2;
}
int isX(int l,int r){
if(dp[l][r]!=-2) return dp[l][r];
if(l==r) return a[st[l]-'a'+1];
if(st[l]=='(' && st[r]==')' ) return dp[l][r]=isX(l+1,r-1);
else{
for(int i=l;i<=r;i++){
if(st[i]=='+'){
int x1=isX(l,i-1);
if(x1<0) continue;
int x2=isX(i+1,r);
if(x2<0) continue;
dp[l][i-1]=x1;dp[i+1][r]=x2;
return dp[l][r]=x1+x2;
}
}
for(int i=l;i<=r;i++){
if(st[i]=='*'){
int x1=isX(l,i-1);
if(x1<0) continue;
int x2=isX(i+1,r);
if(x2<0) continue;
dp[l][i-1]=x1;dp[i+1][r]=x2;
return dp[l][r]=x1*x2;
}
}
return dp[l][r]=-1;
}
}
void computing(){
bool flag=true;
while(flag){
flag=false;
for(int i=0;i<m;i++){
int x1=v[i][0]-'a'+1,x2=v[i][2]-'a'+1;
if(v[i][1]=='<'){
if( a[x1] >= a[x2] ){
a[x2]=a[x1]+1;
flag=true;
}
if( a[x2] > 26){
cout<<"-1"<<endl;
return;
}
}else{
if( a[x1] <= a[x2] ){
a[x1]=a[x2]+1;
flag=true;
}
if( a[x1] > 26){
cout<<"-1"<<endl;
return;
}
}
}
}
cout<<isX(0,st.length()-1)<<endl;
}
int main(){
int t;
cin>>t;
for(int i=1;i<=t;i++){
input();
cout<<"Case "<<i<<": ";
computing();
}
return 0;
}