Codeforces 7E - Defining Macros 題解

Codeforces 7E - Defining Macros 題解

前言

開始使用博客園了,很想寫點東西。(逃c++

這是一道Codeforces題目spa

作法

一道大模擬code

相信你們都看得懂題目意思,我就不贅述了。對象

首先咱們讀進來\(n\)行,對於每一行,咱們把它初步分紅一下四塊內容:遞歸

  • #
  • define
  • 宏的名字
  • 宏的表達式

注意:#define中間可能會有空格,define和宏的名字,宏的名字和宏的表達式之間必定會有空格。ci

如今咱們來處理一下表達式,把它處理到一個序列內,這個序列包含:(,),+,-,*,/,變量,常量字符串

對於每個對象,咱們能夠以下定義:(優先級值越小越優先)get

  • 變量,常量,括號:優先級爲\(0\)
  • /,*:優先級爲\(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!雖然人家是寫掛好屢次的說。。。再看,再看就詛咒你也寫掛!哼~

相關文章
相關標籤/搜索