diff --git a/Algorithm/DP-DynamicProgramming/Bitmask-DP/货郎担问题TSP.cpp b/Algorithm/DP-DynamicProgramming/Bitmask-DP/货郎担问题TSP.cpp new file mode 100644 index 0000000..0221a64 --- /dev/null +++ b/Algorithm/DP-DynamicProgramming/Bitmask-DP/货郎担问题TSP.cpp @@ -0,0 +1,52 @@ +#include +#include +using namespace std; +const int MAX = INT_MAX >> 1; +int main(){ + //n <= 15, S15λĶ + int n; + cin >> n; + //0ʼ + vector> dist(n, vector(n, 0)); + vector> dp(n, vector(1 << n, MAX));//dp[i][S]; + int N = 1 << n; // 2 ^ n; + for(int i = 0; i < n; i++){ + for(int j = 0; j < n; j++){ + cin >> dist[i][j]; + } + } + int start, end; + cin >> start >> end; + dp[start][1 << start] = 0; + //Sij + //ʼ + for(int mask = 0; mask < N; mask++){ + for(int j = 0; j < n; j++){ + if(dp[j][mask] == MAX || !(mask & (1 << j))) continue; + + for(int v = 0; v < n; v++){ + if(mask & (1 << v)) continue; + int new_mask = mask | (1 << v); + //1001 | 0001 = 1001, 1001 ^ 0001 = 1000 + dp[v][new_mask] = min(dp[v][new_mask], dp[j][mask] + dist[j][v]); + } + } + } + // С·յΪ endг + int full_mask = (1 << n) - 1; // гж + int cost = dp[end][full_mask]; + if (cost == MAX) { + cout << "No valid path" << endl; // ûп· + } else { + cout << cost << endl; + } + return 0; +} +/* +4 +0 10 15 20 +10 0 35 25 +15 35 0 30 +20 25 30 0 +0 3 +*/ diff --git a/Algorithm/DS-Related/Graph/BFS/Maze.cpp b/Algorithm/Graph/BFS/Maze.cpp similarity index 100% rename from Algorithm/DS-Related/Graph/BFS/Maze.cpp rename to Algorithm/Graph/BFS/Maze.cpp diff --git a/Algorithm/DS-Related/Graph/DFS/UVa10603-Fill.cpp b/Algorithm/Graph/DFS/UVa10603-Fill.cpp similarity index 100% rename from Algorithm/DS-Related/Graph/DFS/UVa10603-Fill.cpp rename to Algorithm/Graph/DFS/UVa10603-Fill.cpp diff --git a/Algorithm/DS-Related/Graph/DFS/UVa1600Knight-Move betteruseBSF.cpp b/Algorithm/Graph/DFS/UVa1600Knight-Move betteruseBSF.cpp similarity index 100% rename from Algorithm/DS-Related/Graph/DFS/UVa1600Knight-Move betteruseBSF.cpp rename to Algorithm/Graph/DFS/UVa1600Knight-Move betteruseBSF.cpp diff --git a/Algorithm/DS-Related/Graph/DFS/UVa572-Oil-Deposits.cpp b/Algorithm/Graph/DFS/UVa572-Oil-Deposits.cpp similarity index 100% rename from Algorithm/DS-Related/Graph/DFS/UVa572-Oil-Deposits.cpp rename to Algorithm/Graph/DFS/UVa572-Oil-Deposits.cpp diff --git a/Algorithm/DS-Related/Graph/DFS/UVa673-Parentheses-Balance([]).cpp b/Algorithm/Graph/DFS/UVa673-Parentheses-Balance([]).cpp similarity index 100% rename from Algorithm/DS-Related/Graph/DFS/UVa673-Parentheses-Balance([]).cpp rename to Algorithm/Graph/DFS/UVa673-Parentheses-Balance([]).cpp diff --git a/Algorithm/DS-Related/Graph/EulerGraph/UVa-10129-PlayOnWords.cpp b/Algorithm/Graph/EulerGraph/UVa-10129-PlayOnWords.cpp similarity index 100% rename from Algorithm/DS-Related/Graph/EulerGraph/UVa-10129-PlayOnWords.cpp rename to Algorithm/Graph/EulerGraph/UVa-10129-PlayOnWords.cpp diff --git a/Algorithm/Graph/Tree/表达式树/readme.md b/Algorithm/Graph/Tree/表达式树/readme.md new file mode 100644 index 0000000..84261f1 --- /dev/null +++ b/Algorithm/Graph/Tree/表达式树/readme.md @@ -0,0 +1,85 @@ +好的 👍 我来总结一下 **生成表达式树** 的常见方法(只讲思路,不上代码): + +--- + +## 1. **基于后缀表达式(逆波兰式)** + +这是最常见也最简单的方法。 + +* **步骤**: + + 1. 先把中缀表达式(如 `3 + 5 * 2`)转为后缀表达式(`3 5 2 * +`),通常用 **栈** 实现。 + 2. 遍历后缀表达式: + + * 遇到操作数(数字/变量),创建一个叶子节点,压入栈。 + * 遇到运算符,弹出两个节点(右操作数在栈顶),生成一个新运算符节点,把两个节点作为它的左右子树,再把这个新节点压入栈。 + 3. 最后栈中唯一的节点就是整棵表达式树的根。 +* **优点**:逻辑清晰,栈结构天然适合。 +* **应用**:编译器、计算器。 + +--- + +## 2. **基于递归下降 / 文法解析** + +* 将表达式看作一棵语法树,利用递归来解析。 +* **例子**: + + * 一个表达式 `E` 可以分为:`E = T (+/- T)*` + * 一个项 `T` 可以分为:`T = F (*// F)*` + * 一个因子 `F` 可以是:数字 / 变量 / 括号里的子表达式 +* 递归解析时,每一层返回一个子树节点,最后拼成完整的树。 +* **优点**:结构清晰,和正规语法(BNF)一一对应。 +* **应用**:编译器前端、解释器。 + +--- + +## 3. **运算符优先级栈法(Shunting-yard)** + +* 由 Dijkstra 提出的著名算法,本质是把中缀转后缀(再转树)。 +* **步骤**: + + 1. 准备两个栈:运算符栈、操作数栈。 + 2. 依次读入符号: + + * 数字 → 压入操作数栈。 + * 运算符 → 根据优先级处理,出栈已有运算符并生成树节点。 + * 括号 → 特殊处理。 + 3. 最终把所有运算符出栈,并拼接成树。 +* **优点**:不必先生成后缀表达式,直接就能建树。 +* **应用**:表达式求值、解释器。 + +--- + +## 4. **自顶向下(分治法)** + +* 如果你能快速找到当前表达式中 **优先级最低的主运算符**(比如在 `(3+5)*2` 中的 `*`),就可以: + + 1. 把它作为根节点。 + 2. 左右部分递归生成子树。 +* **例子**: + + * 表达式 `3 + 5 * 2 - 4` + * 最外层的最低优先级是 `+` 和 `-`,最右的 `-` 成为根 + * 左边 `3+5*2` 递归成一棵子树,右边 `4` 变叶子 +* **优点**:直观,完全递归化。 +* **缺点**:实现时需要小心括号和优先级。 + +--- + +## 5. **抽象语法树 (AST) 生成** + +* 在编译原理里,语法分析器(Parser)生成的就是 **AST**,本质上就是表达式树。 +* 一般通过 **词法分析 → 语法分析**,然后根据语法规则建树。 +* **特点**:相比一般表达式树,AST 会忽略括号、某些中间节点,只保留运算逻辑。 + +--- + +📌 **总结**: + +* 如果是实际写程序 → 推荐 **方法 1(后缀表达式 + 栈)** 或 **方法 3(Shunting-yard)**。 +* 如果是研究语法 / 编译原理 → 用 **方法 2(递归下降)** 或 **方法 5(AST 生成)**。 +* 如果只是想理解表达式结构 → **方法 4(分治法)** 最直观。 + +--- + +要不要我帮你画几个 **同一个表达式在不同方法下生成的树的对比图**? diff --git a/Algorithm/Graph/Tree/表达式树/后缀分治.cpp b/Algorithm/Graph/Tree/表达式树/后缀分治.cpp new file mode 100644 index 0000000..41a06fa --- /dev/null +++ b/Algorithm/Graph/Tree/表达式树/后缀分治.cpp @@ -0,0 +1,100 @@ +#include +#include +using namespace std; + +template +struct Node{ + T element; + Node* left; + Node* right; + + Node() : element(-1), left(nullptr), right(nullptr) {} + Node(T x) : element(x), left(nullptr), right(nullptr) {} +}; + +template +struct Tree{ + Node* root; + + Tree() : root(nullptr) {} + Tree(Node* x) : root(x) {} + void inOrder(Node* x){ + if(!x) return; + inOrder(x->left); + cout << x->element << " "; + inOrder(x->right); + } + void preOrder(Node* x){ + if(!x) return; + cout << x->element << " "; + preOrder(x->left); + preOrder(x->right); + } + void postOrder(Node* x){ + if(!x) return; + postOrder(x->left); + postOrder(x->right); + cout << x->element << " "; + } +}; + +bool checky(char s){ + if(s == '+' || s == '-' || s == '*' || s == '/') return true; + return false; +} + +int checkb(char s){ + if(s == '(') return 1; + if(s == ')') return -1; + return 0; +} + +//[x, y) +template +Node* build(const string& s, const int& x, const int& y){ + if ((y - x) == 1) return new Node(s[x]); + + // ȥ + if (s[x] == '(' && s[y-1] == ')') { + int cnt = 0; bool ok = true; + for (int i = x; i < y; i++) { + if (s[i] == '(') cnt++; + if (s[i] == ')') cnt--; + if (cnt == 0 && i < y-1) { ok = false; break; } + } + if (ok) return build(s, x+1, y-1); + } + + // ɨ裺 +- */ + for (int pass = 0; pass < 2; pass++) { + int js = 0; + for (int i = y-1; i >= x; i--) { + js += checkb(s[i]); + if (checky(s[i]) && js == 0) { + if ((pass == 0 && (s[i] == '+' || s[i] == '-')) || + (pass == 1 && (s[i] == '*' || s[i] == '/'))) { + Node* tmp = new Node(s[i]); + tmp->right = build(s, i+1, y); + tmp->left = build(s, x, i); + return tmp; + } + } + } + } + + return nullptr; +} + +int main(){ + string a; + cin >> a; + Node* root = build(a, 0, a.size()); + Tree t(root); + t.preOrder(root); + cout << endl; + t.inOrder(root); + cout << endl; + t.postOrder(root); + cout << endl; + return 0; +} diff --git a/Algorithm/Maths/NumberTheory/gcd.cpp b/Algorithm/Maths/NumberTheory/gcd.cpp new file mode 100644 index 0000000..e3af49d --- /dev/null +++ b/Algorithm/Maths/NumberTheory/gcd.cpp @@ -0,0 +1,12 @@ +#include +using namespace std; +int gcd(int a, int b){ + if(b == 0) return a; + return gcd(b, a % b); +} +int main(){ + int a, b; + cin >> a >> b; + cout << gcd(a, b) << endl; + return 0; +}