1. 程式人生 > 其它 >【模擬 + 棧】AcWing 151. 表示式計算4

【模擬 + 棧】AcWing 151. 表示式計算4

這題括號多餘的情況好惡心 orz,以及負數的情況也增加了這題的難度。

分析

首先,解決一般的中綴表示式轉字尾表示式問題:

這裡的運算子包括 +,-,*,/,^,當然,擴大運算子包含的集合的時候我們也可以類似推廣。

考慮用一個答案棧 res 以及運算子棧 ops 來操作。

  • 遇到數字的時候,將它丟入 res
  • 遇到左括號的時候,將它丟入 ops
  • 遇到右括號的時候,開始對 ops 執行出棧操作直到遇到左括號
  • 遇到運算子的時候,只要 ops 棧頂的運算子優先順序高於當前運算子,就一直對 ops 執行出棧操作。

這樣我們就可以將中綴轉字尾了。

下面對字尾表示式求值:
考慮用一個棧維護,
遍歷字尾表示式,當遇到

的時候就丟入棧;否則遇到的是運算子,此時我們將棧頂兩個數拿出來用這個運算子進行運算再將結果丟入棧中。

遍歷完字尾表示式後棧只剩一個數,這就是答案。

至此,原理講述完畢。

但這題很毒瘤,會有括號多餘的情況以及負數的情況。

接下來的操作由為本人亂搞得出,如果找到 hack 資料可以發給我 qwq~,但目前我試了許多奇怪的資料都可以過。

  • 對於括號多餘的情況,考慮對原序列 s 進行一遍類似於括號匹配的操作:維護兩個變數 cntL, cntR,見程式碼:
int cntL=0, cntR=0;
for(auto i: s){
	if(i=='(') cntL++;
	else if(i==')' && cntL) cntL--;
	else if(i==')' && !cntL) cntR++;
}
  • 然後對於負數的情況,例如 -1+3,將 -1 替換為 (0-1)*

實現

// Problem: 表示式計算4
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/153/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;

#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define all(x) (x).begin(), (x).end()

#define int long long

using pii = pair<int, int>;
using ll = long long;

inline void read(int &x){
    int s=0; x=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

map<char, int> mp;

string c2str(char ch){
	string s; s+=ch;
	return s;
}

vector<string> get(string s){
	vector<string> res;
	stack<char> ops;
	
	rep(j,0,s.size()-1){
		char i=s[j];
		if(isdigit(i)){
			string num;
			while(j<s.size() && isdigit(s[j])){
				num+=s[j];
				j++;
			}
			res.pb(num);
			j--;
		}
		else if(i=='(') ops.push('(');
		else if(i==')'){
			while(ops.top()!='('){
				res.pb(c2str(ops.top()));
				ops.pop();
			};
			ops.pop();
		}
		else{
			while(ops.size() && mp[ops.top()]>=mp[i]){
				res.pb(c2str(ops.top()));
				ops.pop();
			}
			ops.push(i);
		}
	}
	while(ops.size()) res.pb(c2str(ops.top())), ops.pop();
	return res;
}

int to_int(string s){
	int res=0;
	for(auto i: s) res=res*10+i-'0';
	return res;
}

int getV(int a, int b, string op){
	if(op=="+") return a+b;
	if(op=="-") return a-b;
	if(op=="*") return a*b;
	if(op=="/") return a/b;
	if(op=="^"){
		int res=1;
		for(; b; b>>=1, a*=a) if(b&1) res=res*a;
		return res;
	}
}

int cal(vector<string> s){
	stack<int> stk;
	for(auto i: s){
		if(!mp.count(i[0])) stk.push(to_int(i));
		else{
			int a=stk.top(); stk.pop();
			int b=stk.top(); stk.pop();
			stk.push(getV(b, a, i));
		}
	}
	return stk.top();
}

signed main(){
	mp['(']=0;
	mp['+']=mp['-']=1;
	mp['*']=mp['/']=2;
	mp['^']=3;

	string str; cin>>str;
	string s;
	rep(i,0,str.size()-1){
		if(i && str[i]=='-' && !isdigit(str[i-1]) || !i && str[i]=='-'){
			if(i && str[i-1]==')') s+="+(0-1)*";
			else s+="(0-1)*";
		}
		else s+=str[i];
	}
	
	int cntL=0, cntR=0;
	for(auto i: s){
		if(i=='(') cntL++;
		else if(i==')' && cntL) cntL--;
		else if(i==')' && !cntL) cntR++;
	}
	while(cntL--) s+=')';
	auto tmp=s;
	s="";
	while(cntR--) s+='(';
	s+=tmp; 
	
	cout<<cal(get(s))<<endl;
	
	return 0;
}