題目:給定不含括號的表達式,僅含正整數(1~20)、+、*,數字個數 ≤12。通過加括號改變運算順序,求表達式的最大值與最小值。
1+2*3+4 → (1+2)*(3+4)=21。1+2*3+4 → 1+(2*3)+4=11。證明直覺:a+b vs a*b(a,b≥1),乘法增長更快。要最大化,盡量讓大數相乘(先加變大再乘);要最小化,盡量讓小數相乘(先乘變小再加)。
兩次掃描,分別模擬兩種優先級:
st。讀數字入棧。讀運算符:*:彈出棧頂 x,讀下一數 y,壓入 x*y。+:直接讀下一數入棧。st。讀數字入棧。讀運算符:+:彈出棧頂 x,讀下一數 y,壓入 x+y。*:直接讀下一數入棧。#include <bits/stdc++.h>
using namespace std;
long long evalMin(const string& s) {
vector st;
long long cur = 0;
char op = '+';
for (size_t i = 0; i <= s.size(); ++i) {
if (i < s.size() && isdigit(s[i])) {
cur = cur * 10 + (s[i] - '0');
} else {
if (op == '+') st.push_back(cur);
else if (op == '*') { st.back() *= cur; }
if (i < s.size()) op = s[i];
cur = 0;
}
}
return accumulate(st.begin(), st.end(), 0LL);
}
long long evalMax(const string& s) {
vector st;
long long cur = 0;
char op = '*';
for (size_t i = 0; i <= s.size(); ++i) {
if (i < s.size() && isdigit(s[i])) {
cur = cur * 10 + (s[i] - '0');
} else {
if (op == '*') st.push_back(cur);
else if (op == '+') { st.back() += cur; }
if (i < s.size()) op = s[i];
cur = 0;
}
}
long long prod = 1;
for (long long v : st) prod *= v;
return prod;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T; cin >> T;
string s;
while (T--) {
cin >> s;
cout << "The maximum and minimum are " << evalMax(s) << " and " << evalMin(s) << ".\n";
}
return 0;
}
| 輸入 | 最大值 | 最小值 | 說明 |
|---|---|---|---|
| 1+2*3*4+5 | 81 | 30 | 樣例 |
| 4*18+14+7*10 | 1560 | 156 | 樣例 |
| 3+11+4*1*13*12*8+3*3+8 | 339768 | 5023 | 樣例 |
| 2*3+4 | 14 | 10 | (2+3)*4=14 vs 2*3+4=10 |
| 指標 | 複雜度 | 說明 |
|---|---|---|
| 時間 | O(L) | L 為表達式長度,單次掃描 |
| 空間 | O(L) | 棧深度 ≤ 數字個數 ≤ 12 |
UVA 10700 是「表達式加括號極值」的經典題。核心洞察:最大值=加優先,最小值=乘優先。這將指數級的括號放置問題轉化為線性掃描棧模擬。掌握此結論,可秒殺同類問題(如 LeetCode 227 基礎計算器 II 的變體)。注意數據範圍:12 個數字最大 20,結果可能超 32 位,必須用 long long(64 位)。