開始使用博客園了,很想寫點東西。(逃c++
這是一道Codeforces題目。spa
一道大模擬code
相信你們都看得懂題目意思,我就不贅述了。對象
首先咱們讀進來\(n\)行,對於每一行,咱們把它初步分紅一下四塊內容:遞歸
#
號define
注意:#
和define
中間可能會有空格,define
和宏的名字,宏的名字和宏的表達式之間必定會有空格。ci
如今咱們來處理一下表達式,把它處理到一個序列內,這個序列包含:(
,)
,+
,-
,*
,/
,變量
,宏
,常量
。字符串
對於每個對象,咱們能夠以下定義:(優先級值越小越優先)get
/
,*
:優先級爲\(1\)+
,-
:優先級爲\(2\)同時咱們能夠發現一個表達式,合法時知足如下條件:博客
/
要求左側對象優先級不大於1,右側對象優先級等於0
*
要求左側對象優先級不大於1,右側對象優先級不大於1
-
要求右側對象優先級不大於1
其他對象不作要求
因而,對於一個表達式\(S\),咱們能夠遞歸地考慮:
空表達式
,常量
,變量
優先級\(0\),
宏
優先級爲內部表達式優先級,合法也取決於內部表達式是否合法
(表達式)
,優先級爲\(0\),合法取決於內部是否合法
表達式+表達式
,表達式-表達式
,合法取決於+
,-
的運算,優先級爲\(2\)
表達式/表達式
,表達式/表達式
,合法取決於*
,/
的運算,優先級爲\(1\)
好了,成了,能夠寫代碼了!
#include<bits/stdc++.h> using namespace std; int n; vector<string> expr[105]; //expr爲id對應的處理好的表達式序列 int prio[105]; //prio爲記憶化處理id對應的表達式的優先級 map<string,int> def; //def爲宏名稱對應的id inline bool valid(int lp,char op,int rp){ //左表達式優先級lp,運算符op,右表達式優先級rp,是否合法 if(op=='/')return lp<=1&&rp<=0; if(op=='*')return lp<=1&&rp<=1; if(op=='+')return lp<=2&&rp<=2; if(op=='-')return lp<=2&&rp<=1; //cerr<<"OP INVALID"<<endl; return false; } int dfs(int id); inline bool isnumber(const string &s){ //string是否存入數字 for(int i=0;i<s.size();i++){ if(s[i]<'0'||s[i]>'9')return false; }return true; } inline bool ismacro(const string &s){ //string是否存入宏 return def.find(s)!=def.end(); } inline bool isvalue(const string &s){ //string是否存入變量 for(int i=0;i<s.size();i++){ if(!isalpha(s[i]))return false; }return true; } int parse(const vector<string> &v,int l,int r){ if(l>=r)return 0;//空表達式 if(l+1==r){//只有一個單獨對象 if(isnumber(v[l])){//是常量 return 0; } if(ismacro(v[l])){//是宏 return dfs(def[v[l]]); } if(isvalue(v[l])){//是變量,要在宏後判斷 return 0; } //cerr<<"PARSING: "<<v[l]<<endl; //cerr<<"PARSE INVALID"<<endl; return -1;//什麼都不是,不可能出現這種狀況(除非寫錯了) } if(v[l]=="("&&v[r-1]==")"){//被括號包裹 bool f=true; int bkc=0; for(int i=l;i<r;i++){//檢查括號配對狀況 if(v[i]=="(")bkc++; if(v[i]==")")bkc--; if(bkc==0&&i+1!=r){ f=false; break; } } if(f){ parse(v,l+1,r-1); return 0; } } int bkc=0; for(int i=r-1;i>=l;i--){//優先找+、-,此處i從小到大亦可 if(v[i]==")")bkc++; if(v[i]=="(")bkc--; if(bkc)continue;//判斷是否在括號內 if(v[i]=="+"){ if(valid(parse(v,l,i),'+',parse(v,i+1,r))){ return 2; }else{ cout<<"Suspicious"<<endl; exit(0);//不合法直接退出 } } if(v[i]=="-"){ if(valid(parse(v,l,i),'-',parse(v,i+1,r))){ return 2; }else{ cout<<"Suspicious"<<endl; exit(0);//不合法直接退出 } } } for(int i=r-1;i>=l;i--){//再找*、/,此處i從小到大亦可 if(v[i]==")")bkc++; if(v[i]=="(")bkc--; if(bkc)continue;//判斷是否在括號內 if(v[i]=="*"){ if(valid(parse(v,l,i),'*',parse(v,i+1,r))){ return 1; }else{ cout<<"Suspicious"<<endl; exit(0);//不合法直接退出 } } if(v[i]=="/"){ if(valid(parse(v,l,i),'/',parse(v,i+1,r))){ return 1; }else{ cout<<"Suspicious"<<endl; exit(0);//不合法直接退出 } } } //cerr<<"PARSING: "<<l<<' '<<r<<endl; //cerr<<"PARSE INVALID"<<endl; return -1;//不可能出現的狀況 } int dfs(int id){//記憶化計算id對應的表達式的優先級 //cerr<<"DFSING IN: "<<id<<endl;cerr<<prio[id]<<endl; if(prio[id]!=-1)return prio[id]; return prio[id]=parse(expr[id],0,expr[id].size()); } vector<string> mkexp(const string &s){//處理原始字符串,得到表達式對象的序列 vector<string> res; for(int i=0;i<s.size();i++){ if(s[i]==' '){ continue; } if(s[i]=='('){ res.push_back("("); continue; } if(s[i]==')'){ res.push_back(")"); continue; } if(s[i]=='+'){ res.push_back("+"); continue; } if(s[i]=='-'){ res.push_back("-"); continue; } if(s[i]=='*'){ res.push_back("*"); continue; } if(s[i]=='/'){ res.push_back("/"); continue; } string tmp; int j; for(j=i;j<s.size()&&(isalpha(s[j])||(s[j]>='0'&&s[j]<='9'));j++){ tmp+=s[j]; } res.push_back(tmp); i=j-1;//常量,宏,變量均可以按照這個方式處理 } return res; } int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n; { string s,t;char c; getline(cin,s); for(int i=1;i<=n;i++){ cin>>c>>s>>s; //特判#號和define分開的狀況 def[s]=i; getline(cin,t); expr[i]=mkexp(t); } getline(cin,t); expr[0]=mkexp(t); } memset(prio,-1,sizeof(prio)); dfs(0); cout<<"OK"<<endl;//因爲不合法會退出,這裏能夠直接輸出合法 return 0; }
祝大家一次AC!雖然人家是寫掛好屢次的說。。。再看,再看就詛咒你也寫掛!哼~