表达式判断 帅呆了的题目

Problem D: 表达式

Time Limit: 1 Sec   Memory Limit: 4 MB
SUBMIT: 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;
}


原文地址:https://www.cnblogs.com/xinyuyuanm/p/2999222.html