Altered
This commit is contained in:
		
							
								
								
									
										52
									
								
								Algorithm/DP-DynamicProgramming/Bitmask-DP/货郎担问题TSP.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								Algorithm/DP-DynamicProgramming/Bitmask-DP/货郎担问题TSP.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <vector>
 | 
			
		||||
using namespace std;
 | 
			
		||||
const int MAX = INT_MAX >> 1;
 | 
			
		||||
int main(){
 | 
			
		||||
	//n <= 15, S<><53><EFBFBD><EFBFBD><EFBFBD><EFBFBD>15λ<35>Ķ<EFBFBD><C4B6><EFBFBD><EFBFBD><EFBFBD> 
 | 
			
		||||
	int n;
 | 
			
		||||
	cin >> n;
 | 
			
		||||
	//<2F><>0<EFBFBD><30>ʼ
 | 
			
		||||
	vector<vector<int>> dist(n, vector<int>(n, 0));
 | 
			
		||||
	vector<vector<int>> dp(n, vector<int>(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;
 | 
			
		||||
	//S<><53><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><C4B3><EFBFBD> 
 | 
			
		||||
	//<2F><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD> 
 | 
			
		||||
	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]);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С·<D0A1><C2B7><EFBFBD><EFBFBD><EFBFBD>յ<EFBFBD>Ϊ end<6E><64><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>г<EFBFBD><D0B3><EFBFBD>
 | 
			
		||||
    int full_mask = (1 << n) - 1; // <20><><EFBFBD>г<EFBFBD><D0B3>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
 | 
			
		||||
    int cost = dp[end][full_mask];
 | 
			
		||||
    if (cost == MAX) {
 | 
			
		||||
        cout << "No valid path" << endl; // û<>п<EFBFBD><D0BF><EFBFBD>·<EFBFBD><C2B7>
 | 
			
		||||
    } 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
 | 
			
		||||
*/
 | 
			
		||||
							
								
								
									
										85
									
								
								Algorithm/Graph/Tree/表达式树/readme.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								Algorithm/Graph/Tree/表达式树/readme.md
									
									
									
									
									
										Normal file
									
								
							@@ -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(分治法)** 最直观。
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
要不要我帮你画几个 **同一个表达式在不同方法下生成的树的对比图**?
 | 
			
		||||
							
								
								
									
										100
									
								
								Algorithm/Graph/Tree/表达式树/后缀分治.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								Algorithm/Graph/Tree/表达式树/后缀分治.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <string>
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
template <class T> 
 | 
			
		||||
struct Node{
 | 
			
		||||
	T element;
 | 
			
		||||
	Node<T>* left;
 | 
			
		||||
	Node<T>* right;
 | 
			
		||||
	
 | 
			
		||||
	Node() : element(-1), left(nullptr), right(nullptr) {}
 | 
			
		||||
	Node(T x) : element(x), left(nullptr), right(nullptr) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
struct Tree{
 | 
			
		||||
	Node<T>* root;
 | 
			
		||||
	
 | 
			
		||||
	Tree() : root(nullptr) {}
 | 
			
		||||
	Tree(Node<T>* x) : root(x) {}
 | 
			
		||||
	void inOrder(Node<T>* x){
 | 
			
		||||
		if(!x) return;
 | 
			
		||||
		inOrder(x->left);
 | 
			
		||||
		cout << x->element << " ";
 | 
			
		||||
		inOrder(x->right);
 | 
			
		||||
	}
 | 
			
		||||
	void preOrder(Node<T>* x){
 | 
			
		||||
		if(!x) return;
 | 
			
		||||
		cout << x->element << " ";
 | 
			
		||||
		preOrder(x->left);
 | 
			
		||||
		preOrder(x->right);
 | 
			
		||||
	}
 | 
			
		||||
	void postOrder(Node<T>* 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 <class T> 
 | 
			
		||||
Node<T>* build(const string& s, const int& x, const int& y){
 | 
			
		||||
    if ((y - x) == 1) return new Node<T>(s[x]);
 | 
			
		||||
 | 
			
		||||
    // ȥ<><C8A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
 | 
			
		||||
    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<T>(s, x+1, y-1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // <20><><EFBFBD><EFBFBD>ɨ<EFBFBD>裺<EFBFBD><E8A3BA> +-<2D><><EFBFBD><EFBFBD> */
 | 
			
		||||
    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<T>* tmp = new Node<T>(s[i]);
 | 
			
		||||
                    tmp->right = build<T>(s, i+1, y);
 | 
			
		||||
                    tmp->left  = build<T>(s, x, i);
 | 
			
		||||
                    return tmp;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(){
 | 
			
		||||
	string a;
 | 
			
		||||
	cin >> a;
 | 
			
		||||
	Node<char>* root = build<char>(a, 0, a.size());
 | 
			
		||||
	Tree<char> t(root); 
 | 
			
		||||
	t.preOrder(root);
 | 
			
		||||
	cout << endl; 
 | 
			
		||||
	t.inOrder(root);
 | 
			
		||||
	cout << endl; 
 | 
			
		||||
	t.postOrder(root);
 | 
			
		||||
	cout << endl; 
 | 
			
		||||
	return 0;
 | 
			
		||||
} 
 | 
			
		||||
							
								
								
									
										12
									
								
								Algorithm/Maths/NumberTheory/gcd.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Algorithm/Maths/NumberTheory/gcd.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
#include <iostream>
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user