Problem D: 表达式
Time Limit: 1 Sec Memory Limit: 4 MBSUBMIT: 375 Solved: 31
[SUBMIT] [STATUS]
Description
设S是一个合法的表达式,E为一个数字字符序列,则合法的表达式可以表示为:E, +E, -E, (S),+(S),-(S),S+(S),S-(S),S*(S),S/(S) 等。(E可以是全‘0’的字符串)。
请注意+S, -S, S+S等不一定是合法的表达式,因为可能出现如“+-E”运算符相邻情况,另外出现“()”括号中没有元素的表达式也是不合法的。
Input
每行一个字符串,最长不超过1023个字符。可能有空行。
Output
如果表达式合法,输入“Yes”,否则输入“No”,然后换行。
如果表达式为空,则输出一个空行。
Sample Input
-1+2+-1+2+(-1+2)()-23
Sample Output
YesNoYesNo
HINT
/*
设S是一个合法的表达式,E为一个数字字符序列,则合法的表达式可以表示为:E, +E, -E, (S),+(S),-(S),S+(S),S-(S),S*(S),S/(S) 等。
(E可以是全‘0’的字符串)。请注意+S, -S, S+S等不一定是合法的表达式,因为可能出现如“+-E”运算符相邻情况,另外出现“()”括号中没有元素的表达式也是不合法的。
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define ORI 0
#define NUM 1
#define CAL 2
#define BCK 3
#define FAIL -1
int f[4][1 << 7];
char buf[1 << 10];
void init()
{
int i;
memset(f, FAIL, sizeof(f)); //二维数组也是可以这样初始化的
//下面的几句代码使得只有输入的是运算符加减乘除 或者数字的时候才能不等于FATL 其它时候全部是FATL 即-1
f[ORI]['+'] = f[ORI]['-'] = f[ORI]['*'] = f[ORI]['/'] = CAL;//我们关心的不是加减乘除 所以忽略主要矛盾 形象化符号
f[NUM]['+'] = f[NUM]['-'] = f[NUM]['*'] = f[NUM]['/'] = CAL;
for(i = '0'; i <= '9'; ++ i) //数字也是按字符输入的 所以要用 其对应的ASCII值
f[ORI][i] = f[NUM][i] = f[CAL][i] = NUM;//把输入的数字 全部变成num=1
f[ORI]['('] = f[CAL]['('] = BCK;
}
void Delete_Blank() ///
{ //
int i, j; //
for(i = j = 0; buf[i]; ++ i) //
if(buf[i] != ' ' && buf[i] != '\t') //
buf[j ++] = buf[i]; //这个地方帅啊 用一个数组就解决了 预处理 哈哈
buf[j] = 0; //
} //
int Find_Bck(int start)
{
int i, cnt = 1;
for(i = start + 1; buf[i]; ++ i)//下面很帅 通过加加 减减 判断( )的平衡
{
if(buf[i] == '(') ++ cnt;
else if(buf[i] == ')') -- cnt;
if(!cnt) return i;
/*这里牛逼啊 已经知道第一个是( 所以初始cnt=1 之后如果遇见) 马上cnt=0了 马上返回)的地址 对()内的内容进行检查
是否有不是正确符号的符号 。 如果 在)之前又发现好多( 则一直加加 直到对称了以后 返回最后一个)地址 然后回溯 DFA
即 再次调用DFA 把括号中的括号内的内容检查一遍
*/
}
return 0;//如果( ) 不对称 则直接返回0
}
bool DFA(int l, int r)
{
int state = ORI, i, nex;
for(i = l; i < r; ++ i)
{
state = f[state][buf[i]];
/*若第一个数是数字 则state此时为1 f[state] 则下次则不是f[0][]而是f[1][]
若第一个不是数字 而是-或+ 则state的值变成了2 如果再下一个字符是加减乘除的话而对应的f[2][]中的内容是-1 即FAIL
避免了2个运算符号同时出现的可能
*/
if(state == BCK)
{
nex = Find_Bck(i);//这时候 已经找到了( 并得到了(的地址给了nex
if(!nex || !DFA(i + 1, nex)) return false;//如果nex不为0 或者 继续调用()内内容发现新的错误 则返回错误表达式
state = NUM;//
i = nex;
}
else if(state == FAIL)//同时出现了两个运算符号
return false;
}
return state == NUM;//如果没有扩号 最后一个 一定是数字 才对 所以判断是否 等于NUM 如果有括号我们直接把state赋值成num就行了
}
int main()
{
init();
while(gets(buf)) //while gets 就行 不用非要等于 NULL
{
Delete_Blank();
if(!buf[0]) {puts("");continue;} //空行就是长度为0的字符串
printf(DFA(0, strlen(buf)) ? "Yes\n" : "No\n");
}
return 0;
}