From 496507453956a88a69a2f115c60c894be6b38a49 Mon Sep 17 00:00:00 2001 From: e2hang <2099307493@qq.com> Date: Thu, 27 Nov 2025 13:40:37 +0800 Subject: [PATCH] Homework New --- .../A 单链表基本操作.cpp | 0 .../B 栈的实现及基本操作.cpp | 0 .../C 队列的实现及基本操作.cpp | 0 .../D KMP模式匹配算法.cpp | 0 Exercise/Homework0/readme.md | 167 ++++++++++++ Exercise/Homework1/Q1.cpp | 43 ++++ Exercise/Homework1/Q2.rs | 50 ++++ Exercise/Homework1/Q3.rs | 39 +++ Exercise/Homework1/readme.md | 242 +++++++----------- Exercise/Homework2/Q1.cpp | 231 ++++++++++++++--- Exercise/{Homework3 => Homework2}/Q1.rs | 0 .../{Homework3 => Homework2}/Q1双栈做法.cpp | 0 .../{Homework3 => Homework2}/Q1过了的版本.cpp | 0 Exercise/Homework2/Q2.rs | 72 ++---- Exercise/Homework2/Q3.rs | 98 ++++--- .../grok的表达式树模板.cpp | 0 Exercise/{Homework3 => Homework2}/readmd.md | 0 Exercise/Homework2/readme.md | 103 -------- .../{Homework3 => Homework2}/表达式树模板.cpp | 0 Exercise/Homework3/Q1.cpp | 214 ---------------- Exercise/Homework3/Q2.rs | 34 --- Exercise/Homework3/Q3.rs | 79 ------ Exercise/Homework3/readme.md | 93 +++++++ .../二叉树查找结点及父结点.cpp} | 0 .../二叉树的创建与遍历.cpp} | 0 .../Q3.cpp => Homework3/重建二叉树.cpp} | 0 Exercise/Homework4/ab间路径.cpp | 198 ++++++++++++++ Exercise/Homework4/readme.md | 156 ++++++----- .../Q1.cpp => Homework4/二叉树删除子树.cpp} | 0 Exercise/Homework4/二叉树和等于某值路径.cpp | 177 +++++++++++++ Exercise/Homework5/Huffman.cpp | 140 ++++++++++ Exercise/Homework5/Huffman2.cpp | 238 +++++++++++++++++ Exercise/Homework5/readme.md | 167 ++++++------ Exercise/Homework5/二叉树每层度为1节点数.cpp | 172 +++++++++++++ Exercise/Homework5/并查集.cpp | 42 +++ Exercise/Homework6/BFS.cpp | 73 ++++++ Exercise/Homework6/DFS.cpp | 42 +++ Exercise/Homework6/readme.md | 123 +++++++++ Exercise/Homework6/图的创建.cpp | 30 +++ 39 files changed, 2191 insertions(+), 832 deletions(-) rename Exercise/{Homework1 => Homework0}/A 单链表基本操作.cpp (100%) rename Exercise/{Homework1 => Homework0}/B 栈的实现及基本操作.cpp (100%) rename Exercise/{Homework1 => Homework0}/C 队列的实现及基本操作.cpp (100%) rename Exercise/{Homework1 => Homework0}/D KMP模式匹配算法.cpp (100%) create mode 100644 Exercise/Homework0/readme.md create mode 100644 Exercise/Homework1/Q1.cpp create mode 100644 Exercise/Homework1/Q2.rs create mode 100644 Exercise/Homework1/Q3.rs rename Exercise/{Homework3 => Homework2}/Q1.rs (100%) rename Exercise/{Homework3 => Homework2}/Q1双栈做法.cpp (100%) rename Exercise/{Homework3 => Homework2}/Q1过了的版本.cpp (100%) rename Exercise/{Homework3 => Homework2}/grok的表达式树模板.cpp (100%) rename Exercise/{Homework3 => Homework2}/readmd.md (100%) delete mode 100644 Exercise/Homework2/readme.md rename Exercise/{Homework3 => Homework2}/表达式树模板.cpp (100%) delete mode 100644 Exercise/Homework3/Q1.cpp delete mode 100644 Exercise/Homework3/Q2.rs delete mode 100644 Exercise/Homework3/Q3.rs create mode 100644 Exercise/Homework3/readme.md rename Exercise/{Homework4/Q2.cpp => Homework3/二叉树查找结点及父结点.cpp} (100%) rename Exercise/{Homework4/Q1.cpp => Homework3/二叉树的创建与遍历.cpp} (100%) rename Exercise/{Homework4/Q3.cpp => Homework3/重建二叉树.cpp} (100%) create mode 100644 Exercise/Homework4/ab间路径.cpp rename Exercise/{Homework5/Q1.cpp => Homework4/二叉树删除子树.cpp} (100%) create mode 100644 Exercise/Homework4/二叉树和等于某值路径.cpp create mode 100644 Exercise/Homework5/Huffman.cpp create mode 100644 Exercise/Homework5/Huffman2.cpp create mode 100644 Exercise/Homework5/二叉树每层度为1节点数.cpp create mode 100644 Exercise/Homework5/并查集.cpp create mode 100644 Exercise/Homework6/BFS.cpp create mode 100644 Exercise/Homework6/DFS.cpp create mode 100644 Exercise/Homework6/readme.md create mode 100644 Exercise/Homework6/图的创建.cpp diff --git a/Exercise/Homework1/A 单链表基本操作.cpp b/Exercise/Homework0/A 单链表基本操作.cpp similarity index 100% rename from Exercise/Homework1/A 单链表基本操作.cpp rename to Exercise/Homework0/A 单链表基本操作.cpp diff --git a/Exercise/Homework1/B 栈的实现及基本操作.cpp b/Exercise/Homework0/B 栈的实现及基本操作.cpp similarity index 100% rename from Exercise/Homework1/B 栈的实现及基本操作.cpp rename to Exercise/Homework0/B 栈的实现及基本操作.cpp diff --git a/Exercise/Homework1/C 队列的实现及基本操作.cpp b/Exercise/Homework0/C 队列的实现及基本操作.cpp similarity index 100% rename from Exercise/Homework1/C 队列的实现及基本操作.cpp rename to Exercise/Homework0/C 队列的实现及基本操作.cpp diff --git a/Exercise/Homework1/D KMP模式匹配算法.cpp b/Exercise/Homework0/D KMP模式匹配算法.cpp similarity index 100% rename from Exercise/Homework1/D KMP模式匹配算法.cpp rename to Exercise/Homework0/D KMP模式匹配算法.cpp diff --git a/Exercise/Homework0/readme.md b/Exercise/Homework0/readme.md new file mode 100644 index 0000000..e62764b --- /dev/null +++ b/Exercise/Homework0/readme.md @@ -0,0 +1,167 @@ +``` html +A 单链表基本操作 +分数 10 +作者 朱允刚 +单位 吉林大学 +请编写程序实现单链表插入、删除结点等基本算法。给定一个单链表和一系列插入、删除结点的操作序列,输出实施上述操作后的链表。单链表数据域值为整数。 + +输入格式: +输入第1行为1个正整数n,表示当前单链表长度;第2行为n个空格间隔的整数,为该链表n个元素的数据域值。第3行为1个正整数m,表示对该链表施加的操作数量;接下来m行,每行表示一个操作,为2个或3个整数,格式为0 k d或1 k。0 k d表示在链表第k个结点后插入一个数据域值为d的结点,若k=0则表示表头插入。1 k表示删除链表中第k个结点,此时k不能为0。注:操作序列中若含有不合法的操作(如在长度为5的链表中删除第8个结点、删除第0个结点等),则忽略该操作。n和m不超过100000。 + +输出格式: +输出为一行整数,表示实施上述m个操作后的链表,每个整数后一个空格。输入数据保证结果链表不空。 + +输入样例: +5 +1 2 3 4 5 +5 +0 2 8 +0 9 6 +0 0 7 +1 0 +1 6 + +输出样例: +7 1 2 8 3 5 + +代码长度限制 +16 KB +Python (python3) +时间限制 +1000 ms +内存限制 +256 MB +Java (javac) +时间限制 +5000 ms +内存限制 +256 MB +其他编译器 +时间限制 +100 ms +内存限制 +10 MB +栈限制 +8192 KB + +--- + +B 栈的实现及基本操作 +分数 10 +作者 朱允刚 +单位 吉林大学 +给定一个初始为空的栈和一系列压栈、弹栈操作,请编写程序输出每次弹栈的元素。栈的元素值均为整数。本题不允许使用stack、queue、vector等STL容器。 + +输入格式: +输入第1行为1个正整数n,表示操作个数;接下来n行,每行表示一个操作,格式为1 d或0。1 d表示将整数d压栈,0表示弹栈。n不超过20000。 + +输出格式: +按顺序输出每次弹栈的元素,每个元素一行。若某弹栈操作不合法(如在栈空时弹栈),则对该操作输出invalid。 + +输入样例: +7 +1 1 +1 2 +0 +0 +0 +1 3 +0 + +输出样例: +2 +1 +invalid +3 + +代码长度限制 +16 KB +时间限制 +50 ms +内存限制 +10 MB +栈限制 +131000 KB + +--- + +C 队列的实现及基本操作 +分数 10 +作者 朱允刚 +单位 吉林大学 +给定一个初始为空的队列和一系列入队、出队操作,请编写程序输出每次出队的元素。队列的元素值均为整数。 +备注:本题不允许使用stack、queue、vector等STL容器。 + +输入格式: +输入第1行为1个正整数n,表示操作个数;接下来n行,每行表示一个操作,格式为1 d或0。1 d表示将整数d入队,0表示出队。n不超过20000。 + +输出格式: +按顺序输出每次出队的元素,每个元素一行。若某出队操作不合法(如在队列空时出队),则对该操作输出invalid。 + +输入样例: +7 +1 1 +1 2 +0 +0 +0 +1 3 +0 + +输出样例: +1 +2 +invalid +3 + +代码长度限制 +16 KB +时间限制 +50 ms +内存限制 +20 MB +栈限制 +8192 KB + +--- + +D KMP模式匹配算法 +分数 10 +作者 朱允刚 +单位 吉林大学 +给定目标串s和模式串p,编写程序使用KMP算法进行模式匹配,计算p在s中首次出现的位置,若p不在s中则输出−1。字符串下标从0开始。 + +输入格式: +输入为2行,第1行为主串s,第2行为模式串p。主串和模式串长度不超过10 +5 + 。 + +输出格式: +输出为2行,第1行为3个整数,表示分别在模式串p的p +m/4 +​ + ,p +2m/4 +​ + ,p +3m/4 +​ + 处失配后,模式串下一次匹配的位置(即next[j]或f[j−1]+1的值,j=m/4,2m/4,3m/4),每个整数后一个空格,m表示模式串p的长度;第2行为一个整数,表示p在s中首次出现的位置,若p不在s中则输出−1。 + +输入样例: +qwerababcabcabcabcdaabcabhlk +abcabcabcabc + +输出样例: +0 3 6 +6 +代码长度限制 +16 KB +时间限制 +20 ms +内存限制 +10 MB +栈限制 +8192 KB + +``` \ No newline at end of file diff --git a/Exercise/Homework1/Q1.cpp b/Exercise/Homework1/Q1.cpp new file mode 100644 index 0000000..2adfe70 --- /dev/null +++ b/Exercise/Homework1/Q1.cpp @@ -0,0 +1,43 @@ +#include +#include +using namespace std; + +int map(char c) { + if (c == '{') return 4; + if (c == '[') return 3; + if (c == '(') return 2; + if (c == '<') return 1; + return 0; +} + +bool match(char a, char b) { + return (a == '(' && b == ')') || (a == '[' && b == ']') || (a == '{' && b == '}') || (a == '<' && b == '>'); +} + +bool check(const string& s) { + string front; + for (int i = 0; i < s.size(); i++) { + if (s[i] == '{' || s[i] == '[' || s[i] == '(' || s[i] == '<') { + if (!front.empty() && map(front.back()) <= map(s[i])) + return false; + front.push_back(s[i]); + } else if (s[i] == '}' || s[i] == ']' || s[i] == ')' || s[i] == '>') { + if (front.empty() || !match(front.back(), s[i])) + return false; + front.pop_back(); + } + } + return front.empty(); +} + +int main() { + int n; + cin >> n; + for (int i = 0; i < n; i++) { + string s; + cin >> s; + cout << (check(s) ? "Match" : "Fail") << endl; + } + return 0; +} + diff --git a/Exercise/Homework1/Q2.rs b/Exercise/Homework1/Q2.rs new file mode 100644 index 0000000..72f2255 --- /dev/null +++ b/Exercise/Homework1/Q2.rs @@ -0,0 +1,50 @@ +use std::io::{self, Read, Write}; + +fn main() { +/* + let mut s = String::new(); + io::stdin().read_line(&mut s).unwrap(); + let n: usize = s.trim().parse().unwrap(); + + let mut nums: Vec = Vec::new(); + let mut max: i64 = 0; + + for _ in 0..n { + let mut x = String::new(); + io::stdin().read_line(&mut x).unwrap(); + let a: i64 = x.trim().parse().unwrap(); + nums.push(a); + if a > max { + max = a; +}*/ +// //输入太慢了过不了 + let mut buf = String::new(); + io::stdin().read_to_string(&mut buf).unwrap(); + let mut it = buf.split_whitespace(); + + let m: usize = it.next().unwrap().parse().unwrap(); + let mut vec: Vec = Vec::with_capacity(m); + let mut max: i64 = 0; + + for _ in 0..m { + let a: i64 = it.next().unwrap().parse().unwrap(); + vec.push(a); + if a > max { max = a; } + } + + let mut dp: Vec = vec![0; (max + 1) as usize]; + if max >= 0 { dp[0] = 1; } + if max >= 1 { dp[1] = 1; } + if max >= 2 { dp[2] = 2; } + if max >= 3 { dp[3] = 4; } + + for i in 4..=max { + dp[i as usize] = dp[(i - 1) as usize] + dp[(i - 2) as usize] + dp[(i - 3) as usize] + dp[(i - 4) as usize]; + } + + let mut out = String::new(); + for i in vec { + out.push_str(&format!("{}\n", dp[i as usize])); + } + io::stdout().write_all(out.as_bytes()).unwrap(); +} diff --git a/Exercise/Homework1/Q3.rs b/Exercise/Homework1/Q3.rs new file mode 100644 index 0000000..84aa215 --- /dev/null +++ b/Exercise/Homework1/Q3.rs @@ -0,0 +1,39 @@ +use std::io; + +pub struct Status{ + pos: i32, + a: char, // from + b: char, // to + c: char // aux +} + + +fn main(){ + let mut s = String::new(); + io::stdin().read_line(&mut s).unwrap(); + let n: i32 = s.trim().parse().unwrap(); + + let mut stack: Vec = Vec::new(); + stack.push(Status{pos: n, a: 'A', b: 'C', c: 'B'}); + let mut max = 0; + + let mut output = String::new(); //输出,要不然太慢总会超时 + + while !stack.is_empty() { + if stack.len() > max { + max = stack.len(); + } + + let mut end = stack.pop().unwrap(); + if end.pos == 1 { + output.push_str(&format!("Move disk from {} to {}\n", end.a, end.b)); + } else { + stack.push(Status{pos: end.pos - 1, a: end.c, b: end.b, c: end.a}); + stack.push(Status{pos: 1, a: end.a, b: end.b, c: end.c}); + stack.push(Status{pos: end.pos - 1, a: end.a, b: end.c, c: end.b}); + + } + } + print!("{}", output); + println!("{}", max); +} \ No newline at end of file diff --git a/Exercise/Homework1/readme.md b/Exercise/Homework1/readme.md index e62764b..5ff1b42 100644 --- a/Exercise/Homework1/readme.md +++ b/Exercise/Homework1/readme.md @@ -1,167 +1,103 @@ -``` html -A 单链表基本操作 -分数 10 -作者 朱允刚 -单位 吉林大学 -请编写程序实现单链表插入、删除结点等基本算法。给定一个单链表和一系列插入、删除结点的操作序列,输出实施上述操作后的链表。单链表数据域值为整数。 +Q1 +``` +编写程序检查给定字符串中包含的括号是否正确匹配,本题中的括号有{ }、[ ]、( )、< >四种。另外再加上一个新的约束条件:当有多种括号嵌套时,嵌套的顺序应为{ → [ → ( → <,即a–g+b∗[(d∗)]、a+[b+(c–d)∗e]都是正确的匹配,而a+(b∗[c+d])则不是正确匹配。注意本题不允许相同类型括号的嵌套,即a+(b∗(c+d))不是正确匹配。本题不需要判断表达式是否合法,只需判断字符串中包含的括号是否正确匹配。 输入格式: -输入第1行为1个正整数n,表示当前单链表长度;第2行为n个空格间隔的整数,为该链表n个元素的数据域值。第3行为1个正整数m,表示对该链表施加的操作数量;接下来m行,每行表示一个操作,为2个或3个整数,格式为0 k d或1 k。0 k d表示在链表第k个结点后插入一个数据域值为d的结点,若k=0则表示表头插入。1 k表示删除链表中第k个结点,此时k不能为0。注:操作序列中若含有不合法的操作(如在长度为5的链表中删除第8个结点、删除第0个结点等),则忽略该操作。n和m不超过100000。 +第一行为一个整数n,表示字符串的个数。接下来n行,每行为一个字符串。1)d]e}x +[()] +((())) +<>()[]{} +[{}] +x=y+{z+(b)} +][() +输出样例1: +Fail +Match +Match +Fail +Match +Fail +Match +Fail +输入样例2: 6 +{[afds(a)]}yt +[()rew] +<>()[wre]{} +[{qw}] +rew{(weq)}jjk +<><{}>[][](){[{}]} +输出样例2: +Match +Match +Match +Fail +Match +Fail 代码长度限制 16 KB 时间限制 -20 ms +50 ms 内存限制 -10 MB +30 MB 栈限制 8192 KB +``` +Q2 +``` +从A点到B点有n个格子,小明现在要从A点到B点,小明吃了些东西,补充了一下体力,他可以一步迈一个格子,也可以一步迈两个格子,也可以一步迈3个格子,也可以一步迈4个格子。请编写程序计算小明从A点到B点一共有多少种走法。 +grid2.jpg + +输入格式: +输入包含多组数据,第一行为一个整数m,m不超过10000,表示输入数据组数。接下来m行,每行为一个整数n(n不超过100,且保证对应的结果小于2 +31 + ),表示从A点到B点的格子数。 + +输出格式: +输出为m个整数,表示对于每组数据小明从A点到B点的走法数。 + +输入样例: +2 +5 +3 +输出样例: +15 +4 +``` + +Q3 +``` +本学期的《数据结构》课上,老师曾结合汉诺塔问题,介绍了使用栈消除递归的方法,从而将汉诺塔问题的递归算法转换为非递归算法,本题请你编程实现上述非递归算法,即使用栈以非递归形式求解汉诺塔问题。将n个圆盘自A柱移至C柱(可途经B柱),并输出求解过中栈的最大容量(最多存储了多少个四元组)。 + +备注:本题将在机器评测后进行人工核验,若有同学未按题目要求,仅使用递归程序通过本题,本题记为0分。 +image.png + +输入格式: +输入为一个整数n,表示初始时A柱上的圆盘数目,n不超过20。 + +输出格式: +按顺序输出各动作,每个动作占一行,格式为“Move disk from x to y”,表示将x柱顶端的圆盘移至y柱。 + +最后一行为一个整数,表示求解过程中栈的最大容量。 + +输入样例: +3 +输出样例: +Move disk from A to C +Move disk from A to B +Move disk from C to B +Move disk from A to C +Move disk from B to A +Move disk from B to C +Move disk from A to C +5 ``` \ No newline at end of file diff --git a/Exercise/Homework2/Q1.cpp b/Exercise/Homework2/Q1.cpp index 2adfe70..d86a6f8 100644 --- a/Exercise/Homework2/Q1.cpp +++ b/Exercise/Homework2/Q1.cpp @@ -1,43 +1,214 @@ #include #include using namespace std; +//뷨ʽм㣨 +//ȻҲջһһ֣ң -int map(char c) { - if (c == '{') return 4; - if (c == '[') return 3; - if (c == '(') return 2; - if (c == '<') return 1; - return 0; +// +long long fastpow(long long d, long long u){ + //d^uÿ + long long result = 1, base = d, b = u; + while(b > 0){ + if(b & 1) result *= base; + base *= base; + b >>= 1; + } + return result; +} +int level(char c){ + switch(c){ + case '+': + case '-': { + return 1; + break; + } + case '*': + case '/': { + return 2; + break; + } + case '^': { + return 3; + break; + } + default: { + return 0; + break; + } + } } -bool match(char a, char b) { - return (a == '(' && b == ')') || (a == '[' && b == ']') || (a == '{' && b == '}') || (a == '<' && b == '>'); -} - -bool check(const string& s) { - string front; - for (int i = 0; i < s.size(); i++) { - if (s[i] == '{' || s[i] == '[' || s[i] == '(' || s[i] == '<') { - if (!front.empty() && map(front.back()) <= map(s[i])) - return false; - front.push_back(s[i]); - } else if (s[i] == '}' || s[i] == ']' || s[i] == ')' || s[i] == '>') { - if (front.empty() || !match(front.back(), s[i])) - return false; - front.pop_back(); +int findexp(const string& s, int l, int r) { + int pos = -1; + int min_level = 114514; + int js = 0; + for (int i = r; i >= l; i--) { + if (s[i] == ')') js--; + else if (s[i] == '(') js++; + + if (js == 0 && level(s[i])) { + // ҽϵ^ʹ<<= + if ((s[i] == '^' && level(s[i]) < min_level) || + (s[i] != '^' && level(s[i]) <= min_level)) { + min_level = level(s[i]); + pos = i; + } } } - return front.empty(); + return pos; } -int main() { - int n; - cin >> n; - for (int i = 0; i < n; i++) { - string s; - cin >> s; - cout << (check(s) ? "Match" : "Fail") << endl; +long long toNum(const string& s, int l, int r) { + long long tmp = 0; + + // ո + while (l <= r && s[l] == ' ') l++; + while (l <= r && s[r] == ' ') r--; + + if (l > r) return 0; + + // Ҵ + for (int i = l; i <= r; i++) { + if (isdigit(s[i])) { + tmp = tmp * 10 + (s[i] - '0'); + } else { + return 0; // Ƿַ + } } - return 0; + + return tmp; } +/* +ŵİ汾 +long long toNum(const string& s, int l, int r){ + long long tmp = 0; + bool neg = false; + if (s[l] == '-') { neg = true; l++; } + for(int i = l; i <= r; i++){ + if(isdigit(s[i])) tmp = tmp * 10 + (s[i] - '0'); + } + return neg ? -tmp : tmp; +} +*/ +struct Node{ + char sign; + long long num; + Node* left; + Node* right; + + Node(): sign('?'), num(-1), left(nullptr), right(nullptr) {} + Node(char s): sign(s), num(-1), left(nullptr), right(nullptr) {} + Node(long long n): sign('?'), num(n), left(nullptr), right(nullptr) {} +}; + +class Expression{ +public: + string exp; + Node* root; + long long result; + bool isValid; + + Expression(const string& s): exp(s), root(nullptr), result(-1), isValid(true) {} + + void inorder(Node* r){ + if(!r) return; + inorder(r->left); + if (r->sign == '?') cout << r->num; + else cout << r->sign; + inorder(r->right); + } + + Node* build(const string& s, int l, int r){ + //[l, r] + //ո + while(l <= r && s[l] == ' ') l++; + while(l <= r && s[r] == ' ') r--; + if(l > r) return nullptr; + //ⲿ + if(s[l] == '(' && s[r] == ')'){ + bool hasQuote = true; + int js = 0; + for(int i = l; i <= r; i++){ + if(s[i] == '(') js++; + else if(s[i] == ')') js--; + + if(js == 0 && i != r){ + hasQuote = false; + break; + } + } + if (hasQuote) return build(s, l + 1, r - 1); + } + + int pos = findexp(s, l, r); + // + if(pos == -1) { + long long x = toNum(s, l, r); + //cout << "*" << r << endl; Ϊʲô0 + return new Node(x); + //·ڵ + } + Node* tmp = new Node(s[pos]); + tmp->left = build(s, l, pos - 1); + tmp->right = build(s, pos + 1, r); + return tmp; + } + + long long calc(Node* r, bool& isValid){ + if(!r) return 0; + // + if(r->sign == '?') return r->num; + + // + long long left = calc(r->left, isValid); + long long right = calc(r->right, isValid); + if(r->num == -1){ + char c = r->sign; + switch(c){ + case '+': return left + right; + case '-': return left - right; + case '*': return left * right; + case '/': { + if(right == 0) { + isValid = false; + return 0; + } + else return left / right; + } + case '^': { + if(left == 0 && right == 0) { isValid = false; return 0; } + return fastpow(left, right); + break; + } + default: return 0; + } + } + } + void print(){ + inorder(root); + } +}; + + + +int main(){ + /* + string s; + getline(cin, s); + Expression tree(s); + tree.root = tree.build(s, 0, s.length() - 1); + //tree.print(); + cout << tree.calc(tree.root, tree.isValid) << endl; + //if(!tree.isValid && result != -1) cout << result < = Vec::new(); - let mut max: i64 = 0; + let mut j = 0; + while j <= str.len() - 5{ + if &str[j..j+5] == core { + js += 1; + j += 5; + if js >= m { + cnt += 1; + } + } else{ + js = 0; + j += 1; + } + } - for _ in 0..n { - let mut x = String::new(); - io::stdin().read_line(&mut x).unwrap(); - let a: i64 = x.trim().parse().unwrap(); - nums.push(a); - if a > max { - max = a; -}*/ -// //输入太慢了过不了 - let mut buf = String::new(); - io::stdin().read_to_string(&mut buf).unwrap(); - let mut it = buf.split_whitespace(); - - let m: usize = it.next().unwrap().parse().unwrap(); - let mut vec: Vec = Vec::with_capacity(m); - let mut max: i64 = 0; - - for _ in 0..m { - let a: i64 = it.next().unwrap().parse().unwrap(); - vec.push(a); - if a > max { max = a; } + println!("{}", cnt); } - - let mut dp: Vec = vec![0; (max + 1) as usize]; - if max >= 0 { dp[0] = 1; } - if max >= 1 { dp[1] = 1; } - if max >= 2 { dp[2] = 2; } - if max >= 3 { dp[3] = 4; } - - for i in 4..=max { - dp[i as usize] = dp[(i - 1) as usize] + dp[(i - 2) as usize] + dp[(i - 3) as usize] + dp[(i - 4) as usize]; - } - - let mut out = String::new(); - for i in vec { - out.push_str(&format!("{}\n", dp[i as usize])); - } - io::stdout().write_all(out.as_bytes()).unwrap(); -} +} \ No newline at end of file diff --git a/Exercise/Homework2/Q3.rs b/Exercise/Homework2/Q3.rs index 84aa215..7b8c251 100644 --- a/Exercise/Homework2/Q3.rs +++ b/Exercise/Homework2/Q3.rs @@ -1,39 +1,79 @@ -use std::io; +use std::io::{self, BufRead}; -pub struct Status{ - pos: i32, - a: char, // from - b: char, // to - c: char // aux + +fn next(s: &Vec, start: usize, end: usize) -> Vec { + let n = end - start; + let mut nxt = vec![0; n]; + let mut j = 0; + for i in 1..n { + while j > 0 && s[start + i] != s[start + j] { + j = nxt[j - 1]; + } + if s[start + i] == s[start + j] { + j += 1; + } + nxt[i] = j; + } + nxt } - fn main(){ - let mut s = String::new(); - io::stdin().read_line(&mut s).unwrap(); - let n: i32 = s.trim().parse().unwrap(); +let stdin = io::stdin(); +for line in stdin.lock().lines() { + let s = line.unwrap(); + if s.trim().is_empty() { continue; } - let mut stack: Vec = Vec::new(); - stack.push(Status{pos: n, a: 'A', b: 'C', c: 'B'}); - let mut max = 0; + let c: Vec = s.trim().chars().collect(); + let n = c.len(); + let mut nxt = next(&c, 0, c.len()); + let mut plen = -1; - let mut output = String::new(); //输出,要不然太慢总会超时 - - while !stack.is_empty() { - if stack.len() > max { - max = stack.len(); + //计算P的话可以直接用最长后缀算,使用KMP + for len in (1..n).rev() { + let mode: Vec = c[n - len..n].to_vec(); + let tmp: Vec = next(&mode, 0, mode.len()); + let mut i = 0; + let mut j = 0; + while i < n - 1 { + while j > 0 && c[i] != mode[j] { + j = tmp[j - 1]; + } + if c[i] == mode[j] { + j += 1; + } + if j == mode.len() { + plen = mode.len() as i32; + break; + } + if plen > 0 { + break; + } + i += 1; } - - let mut end = stack.pop().unwrap(); - if end.pos == 1 { - output.push_str(&format!("Move disk from {} to {}\n", end.a, end.b)); - } else { - stack.push(Status{pos: end.pos - 1, a: end.c, b: end.b, c: end.a}); - stack.push(Status{pos: 1, a: end.a, b: end.b, c: end.c}); - stack.push(Status{pos: end.pos - 1, a: end.a, b: end.c, c: end.b}); - + if plen > 0 { + break; } } - print!("{}", output); - println!("{}", max); + + //计算Q,用len1和len2,如果2 * qlen > len(s),则len(Q) = 0 + + let mut qlen = 0; + if nxt[n - 1] > 0 { + qlen = nxt[nxt[n - 1] - 1]; + } + if 2 * qlen > n { + qlen = 0; + } else { + qlen = n - 2 * qlen; + } + + if plen < 0 { + plen = 0; + } + let out = qlen as i32 + plen as i32; + println!("{}", out); + + //println!("qlen: {}", qlen); + //println!("plen: {}", plen); +} } \ No newline at end of file diff --git a/Exercise/Homework3/grok的表达式树模板.cpp b/Exercise/Homework2/grok的表达式树模板.cpp similarity index 100% rename from Exercise/Homework3/grok的表达式树模板.cpp rename to Exercise/Homework2/grok的表达式树模板.cpp diff --git a/Exercise/Homework3/readmd.md b/Exercise/Homework2/readmd.md similarity index 100% rename from Exercise/Homework3/readmd.md rename to Exercise/Homework2/readmd.md diff --git a/Exercise/Homework2/readme.md b/Exercise/Homework2/readme.md deleted file mode 100644 index 5ff1b42..0000000 --- a/Exercise/Homework2/readme.md +++ /dev/null @@ -1,103 +0,0 @@ -Q1 -``` -编写程序检查给定字符串中包含的括号是否正确匹配,本题中的括号有{ }、[ ]、( )、< >四种。另外再加上一个新的约束条件:当有多种括号嵌套时,嵌套的顺序应为{ → [ → ( → <,即a–g+b∗[(d∗)]、a+[b+(c–d)∗e]都是正确的匹配,而a+(b∗[c+d])则不是正确匹配。注意本题不允许相同类型括号的嵌套,即a+(b∗(c+d))不是正确匹配。本题不需要判断表达式是否合法,只需判断字符串中包含的括号是否正确匹配。 - -输入格式: -第一行为一个整数n,表示字符串的个数。接下来n行,每行为一个字符串。1)d]e}x -[()] -((())) -<>()[]{} -[{}] -x=y+{z+(b)} -][() -输出样例1: -Fail -Match -Match -Fail -Match -Fail -Match -Fail -输入样例2: -6 -{[afds(a)]}yt -[()rew] -<>()[wre]{} -[{qw}] -rew{(weq)}jjk -<><{}>[][](){[{}]} -输出样例2: -Match -Match -Match -Fail -Match -Fail -代码长度限制 -16 KB -时间限制 -50 ms -内存限制 -30 MB -栈限制 -8192 KB -``` -Q2 -``` -从A点到B点有n个格子,小明现在要从A点到B点,小明吃了些东西,补充了一下体力,他可以一步迈一个格子,也可以一步迈两个格子,也可以一步迈3个格子,也可以一步迈4个格子。请编写程序计算小明从A点到B点一共有多少种走法。 - -grid2.jpg - -输入格式: -输入包含多组数据,第一行为一个整数m,m不超过10000,表示输入数据组数。接下来m行,每行为一个整数n(n不超过100,且保证对应的结果小于2 -31 - ),表示从A点到B点的格子数。 - -输出格式: -输出为m个整数,表示对于每组数据小明从A点到B点的走法数。 - -输入样例: -2 -5 -3 -输出样例: -15 -4 -``` - -Q3 -``` -本学期的《数据结构》课上,老师曾结合汉诺塔问题,介绍了使用栈消除递归的方法,从而将汉诺塔问题的递归算法转换为非递归算法,本题请你编程实现上述非递归算法,即使用栈以非递归形式求解汉诺塔问题。将n个圆盘自A柱移至C柱(可途经B柱),并输出求解过中栈的最大容量(最多存储了多少个四元组)。 - -备注:本题将在机器评测后进行人工核验,若有同学未按题目要求,仅使用递归程序通过本题,本题记为0分。 -image.png - -输入格式: -输入为一个整数n,表示初始时A柱上的圆盘数目,n不超过20。 - -输出格式: -按顺序输出各动作,每个动作占一行,格式为“Move disk from x to y”,表示将x柱顶端的圆盘移至y柱。 - -最后一行为一个整数,表示求解过程中栈的最大容量。 - -输入样例: -3 -输出样例: -Move disk from A to C -Move disk from A to B -Move disk from C to B -Move disk from A to C -Move disk from B to A -Move disk from B to C -Move disk from A to C -5 -``` \ No newline at end of file diff --git a/Exercise/Homework3/表达式树模板.cpp b/Exercise/Homework2/表达式树模板.cpp similarity index 100% rename from Exercise/Homework3/表达式树模板.cpp rename to Exercise/Homework2/表达式树模板.cpp diff --git a/Exercise/Homework3/Q1.cpp b/Exercise/Homework3/Q1.cpp deleted file mode 100644 index d86a6f8..0000000 --- a/Exercise/Homework3/Q1.cpp +++ /dev/null @@ -1,214 +0,0 @@ -#include -#include -using namespace std; -//뷨ʽм㣨 -//ȻҲջһһ֣ң - -// -long long fastpow(long long d, long long u){ - //d^uÿ - long long result = 1, base = d, b = u; - while(b > 0){ - if(b & 1) result *= base; - base *= base; - b >>= 1; - } - return result; -} -int level(char c){ - switch(c){ - case '+': - case '-': { - return 1; - break; - } - case '*': - case '/': { - return 2; - break; - } - case '^': { - return 3; - break; - } - default: { - return 0; - break; - } - } -} - -int findexp(const string& s, int l, int r) { - int pos = -1; - int min_level = 114514; - int js = 0; - for (int i = r; i >= l; i--) { - if (s[i] == ')') js--; - else if (s[i] == '(') js++; - - if (js == 0 && level(s[i])) { - // ҽϵ^ʹ<<= - if ((s[i] == '^' && level(s[i]) < min_level) || - (s[i] != '^' && level(s[i]) <= min_level)) { - min_level = level(s[i]); - pos = i; - } - } - } - return pos; -} - -long long toNum(const string& s, int l, int r) { - long long tmp = 0; - - // ո - while (l <= r && s[l] == ' ') l++; - while (l <= r && s[r] == ' ') r--; - - if (l > r) return 0; - - // Ҵ - for (int i = l; i <= r; i++) { - if (isdigit(s[i])) { - tmp = tmp * 10 + (s[i] - '0'); - } else { - return 0; // Ƿַ - } - } - - return tmp; -} -/* -ŵİ汾 -long long toNum(const string& s, int l, int r){ - long long tmp = 0; - bool neg = false; - if (s[l] == '-') { neg = true; l++; } - for(int i = l; i <= r; i++){ - if(isdigit(s[i])) tmp = tmp * 10 + (s[i] - '0'); - } - return neg ? -tmp : tmp; -} -*/ - -struct Node{ - char sign; - long long num; - Node* left; - Node* right; - - Node(): sign('?'), num(-1), left(nullptr), right(nullptr) {} - Node(char s): sign(s), num(-1), left(nullptr), right(nullptr) {} - Node(long long n): sign('?'), num(n), left(nullptr), right(nullptr) {} -}; - -class Expression{ -public: - string exp; - Node* root; - long long result; - bool isValid; - - Expression(const string& s): exp(s), root(nullptr), result(-1), isValid(true) {} - - void inorder(Node* r){ - if(!r) return; - inorder(r->left); - if (r->sign == '?') cout << r->num; - else cout << r->sign; - inorder(r->right); - } - - Node* build(const string& s, int l, int r){ - //[l, r] - //ո - while(l <= r && s[l] == ' ') l++; - while(l <= r && s[r] == ' ') r--; - if(l > r) return nullptr; - //ⲿ - if(s[l] == '(' && s[r] == ')'){ - bool hasQuote = true; - int js = 0; - for(int i = l; i <= r; i++){ - if(s[i] == '(') js++; - else if(s[i] == ')') js--; - - if(js == 0 && i != r){ - hasQuote = false; - break; - } - } - if (hasQuote) return build(s, l + 1, r - 1); - } - - int pos = findexp(s, l, r); - // - if(pos == -1) { - long long x = toNum(s, l, r); - //cout << "*" << r << endl; Ϊʲô0 - return new Node(x); - //·ڵ - } - Node* tmp = new Node(s[pos]); - tmp->left = build(s, l, pos - 1); - tmp->right = build(s, pos + 1, r); - return tmp; - } - - long long calc(Node* r, bool& isValid){ - if(!r) return 0; - // - if(r->sign == '?') return r->num; - - // - long long left = calc(r->left, isValid); - long long right = calc(r->right, isValid); - if(r->num == -1){ - char c = r->sign; - switch(c){ - case '+': return left + right; - case '-': return left - right; - case '*': return left * right; - case '/': { - if(right == 0) { - isValid = false; - return 0; - } - else return left / right; - } - case '^': { - if(left == 0 && right == 0) { isValid = false; return 0; } - return fastpow(left, right); - break; - } - default: return 0; - } - } - } - void print(){ - inorder(root); - } -}; - - - -int main(){ - /* - string s; - getline(cin, s); - Expression tree(s); - tree.root = tree.build(s, 0, s.length() - 1); - //tree.print(); - cout << tree.calc(tree.root, tree.isValid) << endl; - //if(!tree.isValid && result != -1) cout << result <= m { - cnt += 1; - } - } else{ - js = 0; - j += 1; - } - } - - println!("{}", cnt); - } -} \ No newline at end of file diff --git a/Exercise/Homework3/Q3.rs b/Exercise/Homework3/Q3.rs deleted file mode 100644 index 7b8c251..0000000 --- a/Exercise/Homework3/Q3.rs +++ /dev/null @@ -1,79 +0,0 @@ -use std::io::{self, BufRead}; - - -fn next(s: &Vec, start: usize, end: usize) -> Vec { - let n = end - start; - let mut nxt = vec![0; n]; - let mut j = 0; - for i in 1..n { - while j > 0 && s[start + i] != s[start + j] { - j = nxt[j - 1]; - } - if s[start + i] == s[start + j] { - j += 1; - } - nxt[i] = j; - } - nxt -} - -fn main(){ -let stdin = io::stdin(); -for line in stdin.lock().lines() { - let s = line.unwrap(); - if s.trim().is_empty() { continue; } - - let c: Vec = s.trim().chars().collect(); - let n = c.len(); - let mut nxt = next(&c, 0, c.len()); - let mut plen = -1; - - //计算P的话可以直接用最长后缀算,使用KMP - for len in (1..n).rev() { - let mode: Vec = c[n - len..n].to_vec(); - let tmp: Vec = next(&mode, 0, mode.len()); - let mut i = 0; - let mut j = 0; - while i < n - 1 { - while j > 0 && c[i] != mode[j] { - j = tmp[j - 1]; - } - if c[i] == mode[j] { - j += 1; - } - if j == mode.len() { - plen = mode.len() as i32; - break; - } - if plen > 0 { - break; - } - i += 1; - } - if plen > 0 { - break; - } - } - - //计算Q,用len1和len2,如果2 * qlen > len(s),则len(Q) = 0 - - let mut qlen = 0; - if nxt[n - 1] > 0 { - qlen = nxt[nxt[n - 1] - 1]; - } - if 2 * qlen > n { - qlen = 0; - } else { - qlen = n - 2 * qlen; - } - - if plen < 0 { - plen = 0; - } - let out = qlen as i32 + plen as i32; - println!("{}", out); - - //println!("qlen: {}", qlen); - //println!("plen: {}", plen); -} -} \ No newline at end of file diff --git a/Exercise/Homework3/readme.md b/Exercise/Homework3/readme.md new file mode 100644 index 0000000..fe77f27 --- /dev/null +++ b/Exercise/Homework3/readme.md @@ -0,0 +1,93 @@ +Q1 +``` +通过带空指针信息的先根序列(亦称先序序列)创建二叉树,并进行先根(先序)、中根(中序)、后根(后序)遍历。二叉树结点数据域值为不等于0的整数(可能是正数也可能是负数),空指针用0表示,例如1 5 8 0 0 0 6 0 0表示如下图的二叉树。 + +PA567.jpg + +输入格式: +输入为一组用空格间隔的整数,表示带空指针信息的二叉树先根序列。其中空指针信息用0表示。二叉树结点个数不超过150000,高度不超过6000。输入数据保证二叉树各结点数据值互不相等。 + +输出格式: +输出为3行整数,每个整数后一个空格。第1行为该二叉树的先根序列,第2行为中根序列,第3行为后根序列。 + +输入样例: +1 5 8 0 0 0 6 0 0 +输出样例: +1 5 8 6 +8 5 1 6 +8 5 6 1 +代码长度限制 +16 KB +时间限制 +200 ms +内存限制 +20 MB +栈限制 +8192 KB +``` + +Q2 +``` +编写程序在二叉树中查找给定结点及父结点。二叉树结点的数据域值不等于0的整数。 + +输入格式: +输入第1行为一组用空格间隔的整数,表示带空指针信息的二叉树先根序列,其中空指针用0表示。例如1 5 8 0 0 0 6 0 0表示如下图的二叉树。第2行为整数m,表示查询个数。接下来m行,每行为一个不等于0的整数K,表示要查找的结点的数据值。m不超过100,二叉树结点个数不超过150000,高度不超过6000。输入数据保证二叉树各结点数据值互不相等。 + +PA567.jpg + +输出格式: +输出为m行,每行1个整数,表示被查找结点K的父结点数据值,若二叉树中无结点K或结点K无父结点,则输出0。 + +输入样例: +1 5 8 0 0 0 6 0 0 +3 +8 +1 +6 +输出样例: +5 +0 +1 +代码长度限制 +16 KB +时间限制 +300 ms +内存限制 +20 MB +栈限制 +131000 KB +``` + +Q3 +``` +给定非空二叉树的中根序列和后根序列,请编写程序创建该二叉树,计算其高度和先根序列;如给定的中根和后根序列不合法,则亦能识别。 + +输入格式: +输入包含多组数据(不超过10组),每组为两行字符串,第一行表示某二叉树的后根序列,第二行表示其中根序列。结点的值均为A-Z的大写字母,故二叉树结点个数不超过26,且保证输入的两个序列都是结点的全排列,但不一定是合法的中根和后根序列。输入保证不是空二叉树。 + +输出格式: +对于每组数据,如果输入的序列不合法(不是同一棵树的中根序列和后根序列),则输出INVALID;若输入序列合法,输出为两行,第一行为一个整数,表示该二叉树的高度,第二行为一个字符串,表示该二叉树的先根序列。 + +输入样例1: +CEFDBHGA +CBEDFAGH +CBEDFAGH +CEFDBHGA +BCA +CAB + +输出样例1: +3 +ABCDEFGH +INVALID +INVALID + +代码长度限制 +16 KB +时间限制 +50 ms +内存限制 +64 MB +栈限制 +8192 KB +``` \ No newline at end of file diff --git a/Exercise/Homework4/Q2.cpp b/Exercise/Homework3/二叉树查找结点及父结点.cpp similarity index 100% rename from Exercise/Homework4/Q2.cpp rename to Exercise/Homework3/二叉树查找结点及父结点.cpp diff --git a/Exercise/Homework4/Q1.cpp b/Exercise/Homework3/二叉树的创建与遍历.cpp similarity index 100% rename from Exercise/Homework4/Q1.cpp rename to Exercise/Homework3/二叉树的创建与遍历.cpp diff --git a/Exercise/Homework4/Q3.cpp b/Exercise/Homework3/重建二叉树.cpp similarity index 100% rename from Exercise/Homework4/Q3.cpp rename to Exercise/Homework3/重建二叉树.cpp diff --git a/Exercise/Homework4/ab间路径.cpp b/Exercise/Homework4/ab间路径.cpp new file mode 100644 index 0000000..919ff81 --- /dev/null +++ b/Exercise/Homework4/ab间路径.cpp @@ -0,0 +1,198 @@ +#include +#include +#include +#include +using namespace std; +vector> result; +vector leftt, rightt; + +template +struct Node { + T element; + Node* left; + Node* right; + Node* parent; + + Node(const T& e, Node* p) : element(e), parent(p), left(nullptr), right(nullptr) {} +}; + +template +class BinTree { +public: + Node* root; + int height; + vector arr; + + BinTree() : root(nullptr), height(0) {} + BinTree(const vector& arrs) : arr(arrs), height(0) {} + void test() { + for (auto x : arr) { + cout << x << " "; + } + } + Node* returnroot() { + return this->root; + } + + Node* build(int& index, Node* parent) { + if (index >= arr.size() || arr[index] == 0) { + index++; + return nullptr; + } + + Node* node = new Node(arr[index], parent); + index++; + node->left = build(index, node); + node->right = build(index, node); + + return node; + } + + void buildTree() { + int index = 0; + this->root = build(index, nullptr); + } + + //输出 + void preorder(Node* node) { + if (node == nullptr) return; + + cout << node->element << " "; + preorder(node->left); + preorder(node->right); + } + void inorder(Node* node) { + if (node == nullptr) return; + + inorder(node->left); + cout << node->element << " "; + //cout << ( node->parent == nullptr ? 0 : node->parent->element) << endl; + inorder(node->right); + } + void postorder(Node* node) { + if (node == nullptr) return; + + postorder(node->left); + postorder(node->right); + cout << node->element << " "; + } + Node* inorder2(Node* node, const T& x) { + if (node == nullptr) return nullptr; + + if (node->element == x) { + return node; + } + + Node* leftResult = inorder2(node->left, x); + if (leftResult != nullptr) { + return leftResult; + } + + Node* rightResult = inorder2(node->right, x); + return rightResult; + } + void findparent(const T& e) { + auto x = inorder2(this->root, e); + if (x == nullptr || x->parent == nullptr) cout << 0 << endl; + else cout << x->parent->element << endl; + } + void deletesub(Node* node) { + if (node == nullptr) return; + deletesub(node->left); + deletesub(node->right); + delete node; + } + + bool deletenode(const T& e) { + auto x = inorder2(this->root, e); + if (x == nullptr) return false; + + if (x == this->root) { + deletesub(x); + this->root = nullptr; + return true; + } + + if (x->parent->left == x) { + x->parent->left = nullptr; + } else { + x->parent->right = nullptr; + } + deletesub(x); + return true; + } + + void searchpath(T a, T b) { + Node* na = inorder2(root, a); + Node* nb = inorder2(root, b); + if (!na || !nb) { cout << 0 << endl << endl; return; } + + vector*> patha; + Node* cur = na; + while (cur) { + patha.push_back(cur); + cur = cur->parent; + } + reverse(patha.begin(), patha.end()); + + vector*> pathb; + cur = nb; + while (cur) { + pathb.push_back(cur); + cur = cur->parent; + } + reverse(pathb.begin(), pathb.end()); + + int lena = patha.size(), lenb = pathb.size(); + int minlen = min(lena, lenb); + + int idx = 0; + for (int i = 0; i < minlen; ++i) { + if (patha[i] == pathb[i]) idx = i; + else break; + } + + vector allpath; + for (int j = lena - 1; j > idx; j--) { + allpath.push_back(patha[j]->element); + } + allpath.push_back(patha[idx]->element); + for (int j = idx + 1; j < lenb; j++) { + allpath.push_back(pathb[j]->element); + } + + int length = allpath.size() - 1; + cout << length << endl; + + for (int i = 0; i < allpath.size(); ++i) { + cout << allpath[i] << " "; + } + cout << endl; + } +}; + +int main() { + int x = 0; + vector arr; + string line; + getline(cin, line); + stringstream ss(line); + int num; + + while (ss >> num) { + arr.push_back(num); + } + BinTree tree(arr); + tree.buildTree(); + + int m; + cin >> m; + for(int i = 0; i < m; i++){ + int a, b; + cin >> a >> b; + tree.searchpath(a, b); + } + + + return 0; +} \ No newline at end of file diff --git a/Exercise/Homework4/readme.md b/Exercise/Homework4/readme.md index fe77f27..7a3bec9 100644 --- a/Exercise/Homework4/readme.md +++ b/Exercise/Homework4/readme.md @@ -1,87 +1,72 @@ Q1 ``` -通过带空指针信息的先根序列(亦称先序序列)创建二叉树,并进行先根(先序)、中根(中序)、后根(后序)遍历。二叉树结点数据域值为不等于0的整数(可能是正数也可能是负数),空指针用0表示,例如1 5 8 0 0 0 6 0 0表示如下图的二叉树。 +编写程序对给定二叉树执行若干次删除子树操作,输出每次删除子树后剩余二叉树的中根序列。二叉树结点的数据域值为不等于0的整数。每次删除操作是在上一次删除操作后剩下的二叉树上执行。 + +输入格式: +输入第1行为一组用空格间隔的整数,表示带空指针信息的二叉树先根序列,其中空指针信息用0表示。例如1 5 8 0 0 0 6 0 0表示如下图的二叉树。第2行为整数m,表示要进行的删除操作次数。接下来m行,每行一个不等于0的整数K,表示要删除以K为根的子树。m不超过100,二叉树结点个数不超过5000。输入数据保证各结点数据值互不相等,且删除子树后二叉树不为空。 PA567.jpg -输入格式: -输入为一组用空格间隔的整数,表示带空指针信息的二叉树先根序列。其中空指针信息用0表示。二叉树结点个数不超过150000,高度不超过6000。输入数据保证二叉树各结点数据值互不相等。 - 输出格式: -输出为3行整数,每个整数后一个空格。第1行为该二叉树的先根序列,第2行为中根序列,第3行为后根序列。 +输出为m行,每行为一组整数,表示执行删除操作后剩余二叉树的中根序列(中根序列中每个整数后一个空格)。若要删除的子树不在当前二叉树中,则该行输出0(0后无空格)。 输入样例: 1 5 8 0 0 0 6 0 0 +3 +5 +8 +6 输出样例: -1 5 8 6 -8 5 1 6 -8 5 6 1 +1 6 +0 +1 代码长度限制 16 KB 时间限制 -200 ms +100 ms 内存限制 -20 MB +10 MB 栈限制 8192 KB ``` Q2 ``` -编写程序在二叉树中查找给定结点及父结点。二叉树结点的数据域值不等于0的整数。 +已知二叉树结点为不等于0的整数。给定一个整数K,请编写程序找出以根结点为起点叶结点为终点的所有路径中,结点值之和等于K的所有路径。例如K=15,对于下图所示的二叉树t,满足条件的路径有2条,即8-5-2和8-7。若没有满足条件的路径,则亦能识别。 + +img.jpg 输入格式: -输入第1行为一组用空格间隔的整数,表示带空指针信息的二叉树先根序列,其中空指针用0表示。例如1 5 8 0 0 0 6 0 0表示如下图的二叉树。第2行为整数m,表示查询个数。接下来m行,每行为一个不等于0的整数K,表示要查找的结点的数据值。m不超过100,二叉树结点个数不超过150000,高度不超过6000。输入数据保证二叉树各结点数据值互不相等。 - -PA567.jpg +输入为2行,第一行为一组用空格间隔的整数,个数不超过100个,表示带空指针信息的二叉树先根序列,其中空指针信息用0表示。第2行为整数K。 输出格式: -输出为m行,每行1个整数,表示被查找结点K的父结点数据值,若二叉树中无结点K或结点K无父结点,则输出0。 - -输入样例: -1 5 8 0 0 0 6 0 0 -3 -8 -1 -6 -输出样例: -5 -0 -1 -代码长度限制 -16 KB -时间限制 -300 ms -内存限制 -20 MB -栈限制 -131000 KB -``` - -Q3 -``` -给定非空二叉树的中根序列和后根序列,请编写程序创建该二叉树,计算其高度和先根序列;如给定的中根和后根序列不合法,则亦能识别。 - -输入格式: -输入包含多组数据(不超过10组),每组为两行字符串,第一行表示某二叉树的后根序列,第二行表示其中根序列。结点的值均为A-Z的大写字母,故二叉树结点个数不超过26,且保证输入的两个序列都是结点的全排列,但不一定是合法的中根和后根序列。输入保证不是空二叉树。 - -输出格式: -对于每组数据,如果输入的序列不合法(不是同一棵树的中根序列和后根序列),则输出INVALID;若输入序列合法,输出为两行,第一行为一个整数,表示该二叉树的高度,第二行为一个字符串,表示该二叉树的先根序列。 +输出第一行为一个整数,表示满足条件的路径条数;若没有满足条件的路径,则输出0。从第二行开始,每行为一条满足条件的路径,若有多条满足条件的路径,则按从左到右的顺序依次输出,路径中每个结点值后一个空格,若两条不同的路径包含的各结点值恰好相等,则都需输出。 输入样例1: -CEFDBHGA -CBEDFAGH -CBEDFAGH -CEFDBHGA -BCA -CAB - +8 5 1 0 0 2 0 0 7 0 0 +15 输出样例1: -3 -ABCDEFGH -INVALID -INVALID - +2 +8 5 2 +8 7 +输入样例2: +-1 2 0 0 3 0 0 +2 +输出样例2: +1 +-1 3 +输入样例3: +1 1 0 0 1 0 0 +2 +输出样例3: +2 +1 1 +1 1 +输入样例4: +-1 2 0 0 3 0 0 +8 +输出样例4: +0 代码长度限制 16 KB 时间限制 @@ -90,4 +75,61 @@ INVALID 64 MB 栈限制 8192 KB +``` + +Q3 +``` +给定一棵非空二叉树,结点数据域值为互不相等且不等于0的正整数,同时给定两个正整数a和b,请编写程序输出数据域值为a和b的两个结点间的路径和路径长度。注意本题的路径不受父子关系约束,只要两个结点间有边,就算路径。例如下图所示二叉树,7和8间的路径为7 5 8,路径长度为2;6和8间的路径为6 3 5 8,路径长度为3;9和8间的路径为9 2 1 3 5 8,路径长度为5。9和1之间的路径为9 2 1,路径长度为2。 + +223.jpg + +输入格式: +输入第一行为一组用空格间隔的整数,表示带空指针信息的二叉树先根序列,二叉树结点个数不超过150000,高度不超过5000。第二行为一个整数T,表示查询数目。接下来T行,每行两个互不相等的正整数a和b,含义如题目所述,保证a和b一定在二叉树中。 + +输出格式: +对于每个查询输出为两行整数。第一行为1个整数,表示两个结点间的路径长度,第二行为1行整数,每个整数后一个空格,表示路径。 + +输入样例1: +1 2 9 0 0 0 3 5 7 0 0 8 0 0 6 0 0 +3 +7 8 +6 8 +9 8 +输出样例1: +2 +7 5 8 +3 +6 3 5 8 +5 +9 2 1 3 5 8 +输入样例2: +1 2 0 4 0 7 0 0 3 5 0 0 6 8 20 0 0 21 0 0 0 +3 +7 8 +5 8 +20 21 +输出样例2: +6 +7 4 2 1 3 6 8 +3 +5 3 6 8 +2 +20 8 21 +输入样例3: +2 4 3 0 0 8 0 0 10 5 7 9 0 0 1 0 0 17 0 0 6 0 0 +3 +8 3 +9 17 +1 6 +输出样例3: +2 +8 4 3 +3 +9 7 5 17 +4 +1 7 5 10 6 +数据规模: +测试点0-2、5-9:结点个数≤50,树高≤20 +测试点3:4500≤结点个数≤5500,4000≤树高≤5000 +测试点4:130000≤结点个数≤150000,10≤树高≤20 ``` \ No newline at end of file diff --git a/Exercise/Homework5/Q1.cpp b/Exercise/Homework4/二叉树删除子树.cpp similarity index 100% rename from Exercise/Homework5/Q1.cpp rename to Exercise/Homework4/二叉树删除子树.cpp diff --git a/Exercise/Homework4/二叉树和等于某值路径.cpp b/Exercise/Homework4/二叉树和等于某值路径.cpp new file mode 100644 index 0000000..dbab779 --- /dev/null +++ b/Exercise/Homework4/二叉树和等于某值路径.cpp @@ -0,0 +1,177 @@ +#include +#include +#include +#include +using namespace std; +vector> result; + +template +struct Node { + T element; + Node* left; + Node* right; + Node* parent; + + Node(const T& e, Node* p) : element(e), parent(p), left(nullptr), right(nullptr) {} +}; + +template +class BinTree { +public: + Node* root; + int height; + vector arr; + + BinTree() : root(nullptr), height(0) {} + BinTree(const vector& arrs) : arr(arrs), height(0) {} + void test() { + for (auto x : arr) { + cout << x << " "; + } + } + Node* returnroot() { + return this->root; + } + + Node* build(int& index, Node* parent) { + if (index >= arr.size() || arr[index] == 0) { + index++; + return nullptr; + } + + Node* node = new Node(arr[index], parent); + index++; + node->left = build(index, node); + node->right = build(index, node); + + return node; + } + + void buildTree() { + int index = 0; + this->root = build(index, nullptr); + } + + //输出 + void preorder(Node* node) { + if (node == nullptr) return; + + cout << node->element << " "; + preorder(node->left); + preorder(node->right); + } + void inorder(Node* node) { + if (node == nullptr) return; + + inorder(node->left); + cout << node->element << " "; + //cout << ( node->parent == nullptr ? 0 : node->parent->element) << endl; + inorder(node->right); + } + void postorder(Node* node) { + if (node == nullptr) return; + + postorder(node->left); + postorder(node->right); + cout << node->element << " "; + } + Node* inorder2(Node* node, const T& x) { + if (node == nullptr) return nullptr; + + if (node->element == x) { + return node; + } + + Node* leftResult = inorder2(node->left, x); + if (leftResult != nullptr) { + return leftResult; + } + + Node* rightResult = inorder2(node->right, x); + return rightResult; + } + void findparent(const T& e) { + auto x = inorder2(this->root, e); + if (x == nullptr || x->parent == nullptr) cout << 0 << endl; + else cout << x->parent->element << endl; + } + void deletesub(Node* node) { + if (node == nullptr) return; + deletesub(node->left); + deletesub(node->right); + delete node; + } + + bool deletenode(const T& e) { + auto x = inorder2(this->root, e); + if (x == nullptr) return false; + + if (x == this->root) { + deletesub(x); + this->root = nullptr; + return true; + } + + if (x->parent->left == x) { + x->parent->left = nullptr; + } else { + x->parent->right = nullptr; + } + deletesub(x); + return true; + } + +}; + +template +void add(vector& path, Node* n, int sum, int target) { + if (n == nullptr) return; + + sum += n->element; + path.push_back(n->element); + + if (n->left == nullptr && n->right == nullptr && sum == target) { + result.push_back(path); + } + + add(path, n->left, sum, target); + add(path, n->right, sum, target); + + path.pop_back(); +} + + + +int main() { + int x = 0; + vector arr; + string line; + getline(cin, line); + stringstream ss(line); + int num; + + while (ss >> num) { + arr.push_back(num); + } + BinTree tree(arr); + tree.buildTree(); + + int m; + cin >> m;//和 + + vector path; + add(path, tree.root, 0, m); + + if(result.size() == 0) cout << 0 << endl; + else{ + cout << result.size() << endl; + for(auto x: result){ + for(auto y: x){ + cout << y << " "; + } + cout << endl; + } + } + + return 0; +} \ No newline at end of file diff --git a/Exercise/Homework5/Huffman.cpp b/Exercise/Homework5/Huffman.cpp new file mode 100644 index 0000000..64c2f0f --- /dev/null +++ b/Exercise/Homework5/Huffman.cpp @@ -0,0 +1,140 @@ +#include +using namespace std; + +struct Node { + char ch; // ڷҶڵ㣬ch = 0 + int freq; + bool isLeaf; + int firstPos; // ı״γֵλã tie-break + Node *left, *right; + int createOrder; // ˳ţڷǵڵȽ + + Node(char c, int f, int pos, int order) + : ch(c), freq(f), isLeaf(true), firstPos(pos), + left(NULL), right(NULL), createOrder(order) {} + + Node(Node* l, Node* r, int f, int order) + : ch(0), freq(f), isLeaf(false), firstPos(INT_MAX), + left(l), right(r), createOrder(order) {} +}; + +/* + ȶ + 1. ȨֵС + 2. Ȩֵʱ + a. ڵڷǵڵ + b. Ϊڵ firstPos С + c. Ϊǵڵ createOrder С +*/ +struct Cmp { + bool operator()(Node* a, Node* b) { + if (a->freq != b->freq) return a->freq > b->freq; + + // freq ͬ + if (a->isLeaf != b->isLeaf) return a->isLeaf < b->isLeaf; + + if (a->isLeaf) return a->firstPos > b->firstPos; + return a->createOrder > b->createOrder; + } +}; + +unordered_map codeMap; + +// ɹ +void dfs(Node* root, string path) { + if (!root) return; + if (root->isLeaf) { + codeMap[root->ch] = path; + return; + } + dfs(root->left, path + "0"); + dfs(root->right, path + "1"); +} + +// ùƴ +string decode(Node* root, const string& s) { + string result; + Node* cur = root; + for (char c : s) { + if (c == '0') cur = cur->left; + else if (c == '1') cur = cur->right; + else return "INVALID"; + + if (!cur) return "INVALID"; + if (cur->isLeaf) { + result.push_back(cur->ch); + cur = root; + } + } + if (cur != root) return "INVALID"; // δҶڵ + return result; +} + +int main() { + ios::sync_with_stdio(false); + cin.tie(NULL); + + string text, code1, code2; + cin >> text >> code1 >> code2; + + // ͳƳִ & ״γλ + unordered_map freq, firstPos; + for (int i = 0; i < text.size(); i++) { + char c = text[i]; + freq[c]++; + if (!firstPos.count(c)) firstPos[c] = i; + } + + // ȶ + priority_queue, Cmp> pq; + int createId = 0; + + for (auto& p : freq) { + char c = p.first; + int f = p.second; + pq.push(new Node(c, f, firstPos[c], createId++)); + } + + // Ψһ + while (pq.size() > 1) { + Node* a = pq.top(); pq.pop(); + Node* b = pq.top(); pq.pop(); + Node* parent = new Node(a, b, a->freq + b->freq, createId++); + pq.push(parent); + } + + Node* root = pq.top(); + + // ɱ + dfs(root, ""); + + // ѹǰС + int originalBytes = text.size(); + long long bits = 0; + for (char c : text) bits += codeMap[c].size(); + long long compressedBytes = (bits + 7) / 8; + + cout << originalBytes << " " << compressedBytes << "\n"; + + // ĿҪ루ƵͬƵʰ˳ + vector> order; + for (auto& p : freq) { + order.emplace_back(p.second, firstPos[p.first], p.first); + } + sort(order.begin(), order.end()); + + for (auto& t : order) { + char c = get<2>(t); + cout << c << ":" << codeMap[c] << "\n"; + } + + // + string out1 = decode(root, code1); + string out2 = decode(root, code2); + + cout << out1 << "\n"; + cout << out2 << "\n"; + + return 0; +} + diff --git a/Exercise/Homework5/Huffman2.cpp b/Exercise/Homework5/Huffman2.cpp new file mode 100644 index 0000000..368153f --- /dev/null +++ b/Exercise/Homework5/Huffman2.cpp @@ -0,0 +1,238 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +// 记录生成顺序,确保堆里的比较有确定性 +int g_creation_counter = 0; + +// Huffman 节点,记录权值、字符以及左右孩子 +struct HuffmanNode { + int weight; + char character; + HuffmanNode* left; + HuffmanNode* right; + bool is_leaf; + int first_appearance_index; + int creation_order; + + HuffmanNode(int w, char c, int first_idx) + : weight(w), + character(c), + left(nullptr), + right(nullptr), + is_leaf(true), + first_appearance_index(first_idx), + creation_order(numeric_limits::max()) {} + + HuffmanNode(int w, HuffmanNode* l, HuffmanNode* r) + : weight(w), + character('\0'), + left(l), + right(r), + is_leaf(false), + first_appearance_index(numeric_limits::max()), + creation_order(g_creation_counter++) {} + + ~HuffmanNode() { + delete left; + delete right; + } +}; + +// 优先队列里用的比较器,符合题目的几条 tie-break 规则 +struct NodeComparer { + bool operator()(const HuffmanNode* a, const HuffmanNode* b) const { + if (a->weight != b->weight) { + return a->weight > b->weight; + } + + if (a->is_leaf != b->is_leaf) { + return !a->is_leaf && b->is_leaf; + } + + if (a->is_leaf) { + return a->first_appearance_index > b->first_appearance_index; + } else { + return a->creation_order > b->creation_order; + } + } +}; + +// 根据文本构建 Huffman 树,同时补全频率和首出现位置 +HuffmanNode* buildHuffmanTree(const string& text, + map& freq_map, + map& first_occ_map) { + for (size_t i = 0; i < text.size(); ++i) { + const char ch = text[i]; + freq_map[ch]++; + if (!first_occ_map.count(ch)) { + first_occ_map[ch] = static_cast(i); + } + } + + priority_queue, NodeComparer> pq; + g_creation_counter = 0; + + for (const auto& entry : freq_map) { + pq.push(new HuffmanNode(entry.second, entry.first, first_occ_map[entry.first])); + } + + if (pq.empty()) return nullptr; + if (pq.size() == 1) return pq.top(); + + while (pq.size() > 1) { + HuffmanNode* node1 = pq.top(); pq.pop(); + HuffmanNode* node2 = pq.top(); pq.pop(); + + HuffmanNode* parent = new HuffmanNode( + node1->weight + node2->weight, + node1, + node2 + ); + + pq.push(parent); + } + + return pq.top(); +} + +// 递归得到所有字符的编码 +void generateCodes(const HuffmanNode* node, string& buffer, map& codes) { + if (node == nullptr) return; + + if (node->is_leaf) { + codes[node->character] = buffer; + return; + } + + buffer.push_back('0'); + generateCodes(node->left, buffer, codes); + buffer.pop_back(); + + buffer.push_back('1'); + generateCodes(node->right, buffer, codes); + buffer.pop_back(); +} + +// 用树解码,遇到问题就返回 INVALID +string decodeHuffman(const string& encoded_string, const HuffmanNode* root) { + if (root == nullptr || encoded_string.empty()) { + return "INVALID"; + } + + string decoded_text; + const HuffmanNode* current_node = root; + + for (char bit : encoded_string) { + if (bit == '0') { + current_node = current_node->left; + } else if (bit == '1') { + current_node = current_node->right; + } else { + return "INVALID"; + } + + if (!current_node) { + return "INVALID"; + } + + if (current_node->is_leaf) { + decoded_text.push_back(current_node->character); + current_node = root; + } + } + + if (current_node != root) { + return "INVALID"; + } + + return decoded_text; +} + +// 打印时的辅助结构 +struct CharInfo { + char character; + string code; + int frequency; + int first_index; +}; + +// 先比频率,再比出现顺序 +bool compareCharInfo(const CharInfo& a, const CharInfo& b) { + if (a.frequency != b.frequency) { + return a.frequency < b.frequency; + } + return a.first_index < b.first_index; +} + + +// 主流程:建树、算编码、输出信息和解码 +void processHuffman() { + string text, encoded1, encoded2; + + if (!getline(cin, text)) return; + if (!getline(cin, encoded1)) return; + if (!getline(cin, encoded2)) return; + + if (text.empty() || text.length() < 2) return; + + map char_frequency; + map char_first_occurrence; + + HuffmanNode* root = buildHuffmanTree(text, char_frequency, char_first_occurrence); + + if (root == nullptr) { + cout << "0 0" << endl; + return; + } + + map huffman_codes; + string buffer; + generateCodes(root, buffer, huffman_codes); + + int original_size = static_cast(text.length()); + + long long compressed_bits = 0; + for (const auto& pair : char_frequency) { + compressed_bits += static_cast(pair.second) * huffman_codes[pair.first].length(); + } + + int compressed_size = 0; + if (compressed_bits > 0) { + compressed_size = max(1, static_cast(ceil(static_cast(compressed_bits) / 8.0))); + } + + cout << original_size << " " << compressed_size << endl; + + vector char_list; + char_list.reserve(huffman_codes.size()); + for (const auto& pair : huffman_codes) { + char_list.push_back({pair.first, pair.second, char_frequency[pair.first], char_first_occurrence[pair.first]}); + } + + sort(char_list.begin(), char_list.end(), compareCharInfo); + + for (const auto& info : char_list) { + cout << info.character << ":" << info.code << endl; + } + + string decoded1 = decodeHuffman(encoded1, root); + cout << decoded1 << endl; + + string decoded2 = decodeHuffman(encoded2, root); + cout << decoded2 << endl; + + delete root; +} + +int main() { + processHuffman(); + return 0; +} diff --git a/Exercise/Homework5/readme.md b/Exercise/Homework5/readme.md index 7a3bec9..e23f42b 100644 --- a/Exercise/Homework5/readme.md +++ b/Exercise/Homework5/readme.md @@ -1,71 +1,77 @@ Q1 ``` -编写程序对给定二叉树执行若干次删除子树操作,输出每次删除子树后剩余二叉树的中根序列。二叉树结点的数据域值为不等于0的整数。每次删除操作是在上一次删除操作后剩下的二叉树上执行。 +有n颗珍珠,编号为1至n,爸爸和小明做游戏,让小明把这些珍珠串成若干串项链。初始时n颗珍珠摆放在桌子上,每颗珍珠自成一个项链(即相当于有n个项链,每个项链只含一颗珍珠)。 + +每次爸爸让小明做如下操作“a b”,表示将珍珠a所在的项链串在珍珠b所在的项链后面,形成一串新的项链,即a所在项链的第一个珍珠排在b所在项链的最后一个珍珠后面,如果珍珠a和b已在同一项链里,则忽略该操作。 + +请编写程序,输出小明完成爸爸的所有操作后,每个珍珠所在的项链的链头(该项链第一颗珍珠的编号)。 输入格式: -输入第1行为一组用空格间隔的整数,表示带空指针信息的二叉树先根序列,其中空指针信息用0表示。例如1 5 8 0 0 0 6 0 0表示如下图的二叉树。第2行为整数m,表示要进行的删除操作次数。接下来m行,每行一个不等于0的整数K,表示要删除以K为根的子树。m不超过100,二叉树结点个数不超过5000。输入数据保证各结点数据值互不相等,且删除子树后二叉树不为空。 - -PA567.jpg +每个测试点包含多组测试数据,第一行1个整数 T ,表示测试数据组数。对于每组数据,第一行两个整数 n 和 m,分别表示珍珠个数和操作次数。接下来 m 行,每行两个整数a和b,表示爸爸让小明执行的一个操作。T≤5,1≤n, m≤30000,1≤a, b≤n。 输出格式: -输出为m行,每行为一组整数,表示执行删除操作后剩余二叉树的中根序列(中根序列中每个整数后一个空格)。若要删除的子树不在当前二叉树中,则该行输出0(0后无空格)。 +输出为T 行,每行为 n个整数a +1 +​ + a +2 +​ + …a +n +​ + ,每个整数后一个空格,a +i +​ + (1≤i≤n)表示珍珠i所在项链的链头珍珠编号。 输入样例: -1 5 8 0 0 0 6 0 0 -3 -5 -8 -6 +2 +4 2 +2 1 +4 3 +5 4 +1 2 +2 3 +4 5 +1 3 + + 输出样例: -1 6 -0 -1 +1 1 3 3 +3 3 3 5 5 + +数据规模: +测试点0:1 ≤n, m ≤ 10; +测试点1:10 < n, m ≤100; +测试点2:100 < n, m ≤ 1000; +测试点3:1000 < n, m ≤10000; +测试点4:10000 < n, m ≤ 30000。 + 代码长度限制 16 KB 时间限制 100 ms 内存限制 -10 MB +64 MB 栈限制 8192 KB ``` Q2 ``` -已知二叉树结点为不等于0的整数。给定一个整数K,请编写程序找出以根结点为起点叶结点为终点的所有路径中,结点值之和等于K的所有路径。例如K=15,对于下图所示的二叉树t,满足条件的路径有2条,即8-5-2和8-7。若没有满足条件的路径,则亦能识别。 - -img.jpg +编写程序统计一棵非空二叉树中每层度为1的结点的数目,二叉树结点个数不超过100。 输入格式: -输入为2行,第一行为一组用空格间隔的整数,个数不超过100个,表示带空指针信息的二叉树先根序列,其中空指针信息用0表示。第2行为整数K。 +输入为一个字符串,表示带空指针信息的二叉树先根序列。其中空指针信息用#表示,二叉树结点为a-z, A-Z的字母。 输出格式: -输出第一行为一个整数,表示满足条件的路径条数;若没有满足条件的路径,则输出0。从第二行开始,每行为一条满足条件的路径,若有多条满足条件的路径,则按从左到右的顺序依次输出,路径中每个结点值后一个空格,若两条不同的路径包含的各结点值恰好相等,则都需输出。 +输出为若干行,按层数从小到大次序输出二叉树每层度为1的结点个数,即第1行输出第0层度为1的结点个数,第2行输出第1层度为1的结点个数,以此类推。 -输入样例1: -8 5 1 0 0 2 0 0 7 0 0 -15 -输出样例1: +输入样例: +ABD###CE### +输出样例: +0 2 -8 5 2 -8 7 -输入样例2: --1 2 0 0 3 0 0 -2 -输出样例2: -1 --1 3 -输入样例3: -1 1 0 0 1 0 0 -2 -输出样例3: -2 -1 1 -1 1 -输入样例4: --1 2 0 0 3 0 0 -8 -输出样例4: 0 代码长度限制 16 KB @@ -79,57 +85,40 @@ img.jpg Q3 ``` -给定一棵非空二叉树,结点数据域值为互不相等且不等于0的正整数,同时给定两个正整数a和b,请编写程序输出数据域值为a和b的两个结点间的路径和路径长度。注意本题的路径不受父子关系约束,只要两个结点间有边,就算路径。例如下图所示二叉树,7和8间的路径为7 5 8,路径长度为2;6和8间的路径为6 3 5 8,路径长度为3;9和8间的路径为9 2 1 3 5 8,路径长度为5。9和1之间的路径为9 2 1,路径长度为2。 - -223.jpg +编写一个哈夫曼编码译码程序。针对一段文本,根据文本中字符出现频率构造哈夫曼树,给出每个字符的哈夫曼编码,并进行译码,计算编码前后文本大小。 +为确保构建的哈夫曼树唯一,本题做如下限定: +选择根结点权值最小的两棵二叉树时,选取权值较小者作为左子树。 +若多棵二叉树根结点权值相等,则先生成的作为左子树,后生成的作为右子树,具体来说:i) 对于单结点二叉树,优先选择根结点对应字母在文本中最先出现者,如文本为cba,三个字母均出现1次,但c在文本中最先出现,b第二出现,故则选择c作为左子树,b作为右子树。ii) 对于非单结点二叉树,先生成的二叉树作为左子树,后生成的二叉树作为右子树。iii. 若单结点和非单结点二叉树根结点权值相等,优先选择单结点二叉树。 +生成哈夫曼编码时,哈夫曼树左分支标记为0,右分支标记为1。 输入格式: -输入第一行为一组用空格间隔的整数,表示带空指针信息的二叉树先根序列,二叉树结点个数不超过150000,高度不超过5000。第二行为一个整数T,表示查询数目。接下来T行,每行两个互不相等的正整数a和b,含义如题目所述,保证a和b一定在二叉树中。 +输入为3行。第1行为一个字符串,包含不超过5000个字符,至少包含两个不同的字符,每个字符为a-z的小写字母。第2、3行为两个由0、1组成的字符串,表示待译码的哈夫曼编码。 输出格式: -对于每个查询输出为两行整数。第一行为1个整数,表示两个结点间的路径长度,第二行为1行整数,每个整数后一个空格,表示路径。 +输出第一行为用空格间隔的2个整数,分别为压缩前后文本大小,以字节为单位,一个字符占1字节,8个二进制位占1字节,若压缩后文本不足8位,则按1字节算。输出从第二行开始,每行为1个字符的哈夫曼编码,按各字符在文本中出现次数递增顺序输出,若多个字符出现次数相同,则按其在文本出现先后排列。每行格式为“字母:编码”。最后两行为两行字符串,表示译码结果,若译码失败,则输出INVALID。 -输入样例1: -1 2 9 0 0 0 3 5 7 0 0 8 0 0 6 0 0 -3 -7 8 -6 8 -9 8 -输出样例1: -2 -7 5 8 -3 -6 3 5 8 -5 -9 2 1 3 5 8 -输入样例2: -1 2 0 4 0 7 0 0 3 5 0 0 6 8 20 0 0 21 0 0 0 -3 -7 8 -5 8 -20 21 -输出样例2: -6 -7 4 2 1 3 6 8 -3 -5 3 6 8 -2 -20 8 21 -输入样例3: -2 4 3 0 0 8 0 0 10 5 7 9 0 0 1 0 0 17 0 0 6 0 0 -3 +输入样例: +cbaxyyzz +0100 +011 + +输出样例: 8 3 -9 17 -1 6 -输出样例3: -2 -8 4 3 -3 -9 7 5 17 -4 -1 7 5 10 6 -数据规模: -测试点0-2、5-9:结点个数≤50,树高≤20 -测试点3:4500≤结点个数≤5500,4000≤树高≤5000 -测试点4:130000≤结点个数≤150000,10≤树高≤20 +c:100 +b:101 +a:110 +x:111 +y:00 +z:01 +zy +INVALID + +代码长度限制 +16 KB +时间限制 +50 ms +内存限制 +64 MB +栈限制 +8192 KB ``` \ No newline at end of file diff --git a/Exercise/Homework5/二叉树每层度为1节点数.cpp b/Exercise/Homework5/二叉树每层度为1节点数.cpp new file mode 100644 index 0000000..ac20ee9 --- /dev/null +++ b/Exercise/Homework5/二叉树每层度为1节点数.cpp @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +using namespace std; + +template +struct Node { + T element; + Node* left; + Node* right; + Node* parent; + + Node(const T& e, Node* p) : element(e), parent(p), left(nullptr), right(nullptr) {} +}; + +template +class BinTree { +public: + Node* root; + int height; + vector arr; + deque*> level; + + BinTree() : root(nullptr), height(0) {} + BinTree(const vector& arrs) : arr(arrs), height(0) { } + void test() { + for (auto x : arr) { + cout << x << " "; + } + } + Node* returnroot() { + return this->root; + } + + Node* build(int& index, Node* parent) { + if (index >= arr.size() || arr[index] == '#') { + index++; + return nullptr; + } + + Node* node = new Node(arr[index], parent); + index++; + node->left = build(index, node); + node->right = build(index, node); + + return node; + } + + void buildTree() { + int index = 0; + this->root = build(index, nullptr); + } + + //输出 + void preorder(Node* node) { + if (node == nullptr) return; + + cout << node->element << " "; + preorder(node->left); + preorder(node->right); + } + void inorder(Node* node) { + if (node == nullptr) return; + + inorder(node->left); + cout << node->element << " "; + //cout << ( node->parent == nullptr ? 0 : node->parent->element) << endl; + inorder(node->right); + } + void postorder(Node* node) { + if (node == nullptr) return; + + postorder(node->left); + postorder(node->right); + cout << node->element << " "; + } + Node* inorder2(Node* node, const T& x) { + if (node == nullptr) return nullptr; + + if (node->element == x) { + return node; + } + + Node* leftResult = inorder2(node->left, x); + if (leftResult != nullptr) { + return leftResult; + } + + Node* rightResult = inorder2(node->right, x); + return rightResult; + } + void findparent(const T& e) { + auto x = inorder2(this->root, e); + if (x == nullptr || x->parent == nullptr) cout << 0 << endl; + else cout << x->parent->element << endl; + } + void deletesub(Node* node) { + if (node == nullptr) return; + deletesub(node->left); + deletesub(node->right); + delete node; + } + + bool deletenode(const T& e) { + auto x = inorder2(this->root, e); + if (x == nullptr) return false; + + if (x == this->root) { + deletesub(x); + this->root = nullptr; + return true; + } + + if (x->parent->left == x) { + x->parent->left = nullptr; + } else { + x->parent->right = nullptr; + } + deletesub(x); + return true; + } + + void flatten(){ + level.push_back(root); + while(!level.empty()){ + int floor = level.size(); + int tmp = floor; + int cnt = 0; + int js = 0; + while(tmp--){ + cnt = 0; + auto head = level.begin(); + auto node = *head; + if(node->left) { + level.push_back(node->left); + cnt++; + } + if(node->right) { + level.push_back(node->right); + cnt++; + } + level.pop_front(); + + if(cnt == 1){ + js++; + } + } + + cout << js << endl; + } + } +}; + +int main() { + int x = 0; + vector arr; + string line; + getline(cin, line); + stringstream ss(line); + char num; + + while (ss >> num) { + arr.push_back(num); + } + BinTree tree(arr); + tree.buildTree(); + + tree.flatten(); + return 0; +} \ No newline at end of file diff --git a/Exercise/Homework5/并查集.cpp b/Exercise/Homework5/并查集.cpp new file mode 100644 index 0000000..9651fe6 --- /dev/null +++ b/Exercise/Homework5/并查集.cpp @@ -0,0 +1,42 @@ +//并查集 + 链表 +#include +#include +using namespace std; + +vector parent; + +int find(int x){ + if(parent[x] != x) parent[x] = find(parent[x]); + return parent[x]; +} +void merge(int x, int y){ + auto ax = find(x); + auto ay = find(y); + + if(ax != ay) parent[ax] = ay; +} + +int main(){ + int t; + cin >> t; + for(int i = 0; i < t; i++){ + parent.clear(); + int n, m; + cin >> n >> m; + parent.resize(n); + for(int j = 0; j < n; j++){ + parent[j] = j; + } + for(int j = 0; j < m; j++){ + int a, b; + cin >> a >> b; + merge(a - 1, b - 1); + } + for(int j = 0; j < n; j++){ + cout << find(j) + 1 << " "; + } + cout << endl; + } + + return 0; +} \ No newline at end of file diff --git a/Exercise/Homework6/BFS.cpp b/Exercise/Homework6/BFS.cpp new file mode 100644 index 0000000..a72f074 --- /dev/null +++ b/Exercise/Homework6/BFS.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include +using namespace std; + +int startx, starty, endx, endy; +vector> map; +vector> visited; +int n, m, t; + +int dx[] = {0, 0, 1, -1}; +int dy[] = {1, -1, 0, 0}; +int ans = 1145141919; + +bool isvalid(int x, int y) { + return x >= 0 && x < n && y >= 0 && y < m && map[x][y] != 1 && !visited[x][y]; +} + +int bfs(int startx, int starty){ + queue> q; + q.push(make_tuple(startx, starty, 0)); + visited[startx][starty] = true; + while (!q.empty()) { + int x = get<0>(q.front()); + int y = get<1>(q.front()); + int step = get<2>(q.front()); + q.pop(); + if (x == endx && y == endy) { + return step; + } + for (int i = 0; i < 4; i++) { + int nx = x + dx[i]; + int ny = y + dy[i]; + if (isvalid(nx, ny)) { + q.push(make_tuple(nx, ny, step + 1)); + visited[nx][ny] = true; + } + } + } + return 1145141919; +} + +int main(){ + while (cin >> n >> m >> t) { + map.assign(n, vector(m)); + visited.assign(n, vector(m, false)); + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + cin >> map[i][j]; + if (map[i][j] == 3) { + startx = i; + starty = j; + } + if (map[i][j] == 4) { + endx = i; + endy = j; + } + } + } + visited[startx][starty] = true; + ans = bfs(startx, starty); + if (ans == 1145141919) { + cout << "can not save" << endl; + continue; + } + int maxs = min(t, ans); + int saved = maxs > 0 ? maxs - 1 : 0; + cout << ans - saved << endl; + } + return 0; +} + diff --git a/Exercise/Homework6/DFS.cpp b/Exercise/Homework6/DFS.cpp new file mode 100644 index 0000000..ebccbfa --- /dev/null +++ b/Exercise/Homework6/DFS.cpp @@ -0,0 +1,42 @@ + +#include +#include +#include +#include + +using namespace std; + +vector> adj; +vector visited; +void dfs(int u){ + visited[u] = true; + cout << u << " "; + for(int v : adj[u]){ + if(!visited[v]){ + dfs(v); + } + } +} + +int main() { + int n, m; + cin >> n >> m; + adj.resize(n); + visited.resize(n); + for (int i = 0; i < m; i++) { + int u, v; + cin >> u >> v; + adj[u].push_back(v); + } + for(int i = 0; i < n; i++) { + sort(adj[i].begin(), adj[i].end()); + } + dfs(0); + + for(int i = 0; i < n; i++) { + if(!visited[i]) { + dfs(i); + } + } + return 0; +} \ No newline at end of file diff --git a/Exercise/Homework6/readme.md b/Exercise/Homework6/readme.md new file mode 100644 index 0000000..0ae4867 --- /dev/null +++ b/Exercise/Homework6/readme.md @@ -0,0 +1,123 @@ +Q1 +``` +请编写程序创建一个有向图。有向图中包含n个顶点,编号为0至n-1。 + +输入格式: +输入第一行为两个正整数n和e,分别表示图的顶点数和边数,其中n不超过20000,e不超过20000。接下来e行表示每条边的信息,每行为3个非负整数a、b、c,其中a和b表示该边的端点编号,c表示权值。各边并非按端点编号顺序排列。 + +输出格式: +按顶点编号递增顺序输出每个顶点引出的边,每个顶点占一行,若某顶点没有引出边,则不输出。每行表示一个顶点引出的所有边,格式为a:(a,b,w)……,表示有向边a->b的权值为w,a引出的多条边按编号b的递增序排列。 + +输入样例: +7 7 +0 1 5 +0 3 7 +0 6 6 +1 2 4 +2 5 1 +3 5 3 +6 5 4 + +输出样例: +0:(0,1,5)(0,3,7)(0,6,6) +1:(1,2,4) +2:(2,5,1) +3:(3,5,3) +6:(6,5,4) + +代码长度限制 +16 KB +时间限制 +500 ms +内存限制 +20 MB +栈限制 +8192 KB +``` + +Q2 +``` +唐僧被妖精抓到了妖洞里,悟空前往解救。妖洞由n行m列单元格组成。有的单元格是空地,可以走;有的单元格处是墙壁,不能走。假定悟空只可以朝上、下、左、右四个方向走,不能斜着走,悟空每行进一个位置(单元格)需要1分钟。此外,悟空有一种超能力,可以在1分钟瞬时移动最多T步(即1分钟行进最多T个单元格),但受体力限制,这种超能力只能使用一次。给定妖洞地图、悟空的位置、唐僧的位置,请编写程序计算悟空解救唐僧所需要的最短时间。 +image.png + +输入格式: +输入包含多组数据。每组数据第一行是3个整数n、m、T (1≤ n, m, T ≤100),含义如题目所述;接下来是n行,每行m个数字,表示整个地图。空地格子用0表示,墙壁用1表示,悟空所在位置用3表示,唐僧的位置用4表示。 + +输出格式: +对于每组数据,如果悟空能够解救到唐僧,输出一个整数,表示悟空到唐僧所在位置所需的最短时间,如果不能到达唐僧所在位置,输出“can not save”。 + +输入样例1: +5 5 2 +1 0 1 1 1 +1 0 4 1 0 +1 0 0 1 0 +0 0 0 1 0 +1 0 3 0 1 +5 5 3 +3 0 1 1 1 +1 0 1 1 0 +1 0 1 1 0 +0 0 0 1 0 +1 0 1 0 4 + +输出样例1: +2 +can not save + +输入样例2: +7 8 5 +1 0 1 1 1 1 1 0 +1 0 4 1 0 0 3 0 +1 0 0 1 0 0 0 0 +0 0 1 0 0 1 0 1 +1 0 0 0 1 1 0 0 +0 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 + +输出样例2: +8 + +代码长度限制 +16 KB +时间限制 +10 ms +内存限制 +64 MB +栈限制 +8192 KB +``` + +Q3 +``` +编写程序对给定的有向图(不一定连通)进行深度优先遍历,图中包含n个顶点,编号为0至n-1。本题限定在深度优先遍历过程中,如果同时出现多个待访问的顶点,则优先选择编号最小的一个进行访问,以顶点0为遍历起点。 + +输入格式: +输入第一行为两个整数n和e,分别表示图的顶点数和边数,其中n不超过20000,e不超过50。接下来e行表示每条边的信息,每行为两个整数a、b,表示该边的端点编号,但各边并非按端点编号顺序排列。 + +输出格式: +输出为一行整数,每个整数后一个空格,即该有向图的深度优先遍历结点序列。 + +输入样例1: +3 3 +0 1 +1 2 +0 2 +输出样例1: +0 1 2 +输入样例2: +4 4 +0 2 +0 1 +1 2 +3 0 +输出样例2: +0 1 2 3 +代码长度限制 +16 KB +时间限制 +50 ms +内存限制 +64 MB +栈限制 +65536 KB +``` \ No newline at end of file diff --git a/Exercise/Homework6/图的创建.cpp b/Exercise/Homework6/图的创建.cpp new file mode 100644 index 0000000..9d039a2 --- /dev/null +++ b/Exercise/Homework6/图的创建.cpp @@ -0,0 +1,30 @@ + +#include +#include +#include +#include + +using namespace std; + +int main() { + int n, m; + cin >> n >> m; + vector>> adj(n); + //DAG + for (int i = 0; i < m; i++) { + int u, v, w; + cin >> u >> v >> w; + adj[u].push_back({v, w}); + } + for(int i = 0; i < n; i++) { + if(adj[i].size() > 0) { + sort(adj[i].begin(), adj[i].end()); + cout << i << ":"; + for(auto [v, w] : adj[i]) { + cout << "(" << i << "," << v << "," << w << ")"; + } + cout << endl; + } + } + return 0; +} \ No newline at end of file