算法专栏(按时间排序)王道考研机试指南代码合集 王道考研机试指南重写 算法分析上机作业 leetcode记录 leetcode记录2 牛客网刷题记录与企业机试记录
前言 几年前为了应付有些学校的机试,大概刷了一遍《王道考研机试指南》这本书里的代码王道考研机试指南代码合集 。几年过去了想重新刷一遍,加强一下算法能力,同时也熟悉c++的新特性。以下代码不注重算法性能,而是尽可能使用一些新特性并保持代码规范(尝试规范)Google 开源项目风格指南 。
代码随缘写,章节也不固定 代码环境:linux vscode
Makefile文件(改别人博客上的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 .PHONY: all clean SRC=$(wildcard *.cpp) BIN=$(SRC:%.cpp=%) CC=g++ CXXFLAGS=-Wall -g -std=c++2a -o all:$(BIN) $(BIN):%:%.cpp $(CC) $^ $(CXXFLAGS) $@ clean: rm $(BIN)
数据结构一章 栈的应用 括号匹配问题 题目链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <iostream> #include <stack> #include <string> class Solution {public : bool IsMatch (const std::string &s) { std::stack<char > symbol_stack; std::string left_bracket = "{[(" ; std::string right_bracket = "}])" ; char top_char; for (auto c : s) { if (left_bracket.find (c) != left_bracket.npos) { symbol_stack.emplace (c); } else { auto pos = right_bracket.find (c); if (pos != right_bracket.npos) { if (symbol_stack.empty ()) { return false ; } top_char = symbol_stack.top (); if (top_char != left_bracket[pos]) { return false ; } symbol_stack.pop (); } } } return true ; } };int main () { Solution solution; std::string input; std::cin >> input; bool ans = solution.IsMatch (input); if (ans) { std::cout << "true" << std::endl; } else { std::cout << "false" << std::endl; } }
简单计算器 题目链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <iostream> #include <stack> #include <string> #include <tuple> class Solution { public : void SetExpr (const std::string &expr) ; double GetExprValue () ; private : auto GetNumber (std::size_t pos) const ; int GetOpPriority (char op) const ; void ProcessSymbol (char symbol) ; std::string expr_; std::stack<char > symbol_stack_; std::stack<double > number_stack_; std::string operators_; char markup_char_{'m' }; };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 #include "simple_calculator.h" auto Solution::GetNumber (std::size_t pos) const { double res = 0 ; while (expr_[pos] != ' ' ) { res = res * 10 + expr_[pos] - '0' ; pos++; } return std::make_tuple (res, pos); }int Solution::GetOpPriority (char op) const { if (op == '*' || op == '/' ) { return 3 ; } if (op == '+' || op == '-' ) { return 2 ; } if (op == markup_char_) { return 1 ; } return 0 ; }void Solution::ProcessSymbol (char symbol) { int symbol_priority = GetOpPriority (symbol); char top_symbol = symbol_stack_.top (); int top_priority = GetOpPriority (top_symbol); if (symbol_priority > top_priority) { symbol_stack_.emplace (symbol); } else { if (top_symbol == markup_char_) { return ; } double lhs, rhs, res; rhs = number_stack_.top (); number_stack_.pop (); lhs = number_stack_.top (); number_stack_.pop (); switch (top_symbol) { case '+' : { res = lhs + rhs; break ; } case '-' : { res = lhs - rhs; break ; } case '*' : { res = lhs * rhs; break ; } case '/' : { res = lhs / rhs; break ; } } number_stack_.emplace (res); symbol_stack_.pop (); ProcessSymbol (symbol); } }void Solution::SetExpr (const std::string &expr) { expr_ = expr + " " + markup_char_; operators_ = "+-*/" ; operators_ += markup_char_; while (!symbol_stack_.empty ()) { symbol_stack_.pop (); } symbol_stack_.emplace (markup_char_); while (!number_stack_.empty ()) { number_stack_.pop (); } }double Solution::GetExprValue () { std::size_t expr_len = expr_.length (); for (std::size_t i = 0 ; i < expr_len; i++) { if (operators_.find (expr_[i]) != operators_.npos) { ProcessSymbol (expr_[i]); } else if (expr_[i] != ' ' ) { auto [res, new_pos] = GetNumber (i); i = new_pos; number_stack_.emplace (res); } } return number_stack_.top (); }int main () { Solution solution; std::string expr; double ans; while (getline (std::cin, expr)) { if (expr.length () == 1 && expr[0 ] == '0' ) { break ; } solution.SetExpr (expr); ans = solution.GetExprValue (); printf ("%.2f\n" , ans); } return 0 ; }
在这里我将代码写成两个文件一是因为函数比较多,全部写在类里有点难看。二是因为GetNumber函数的返回类型使用的是自动类型推导,但当GetExprValue调用它时,auto还没有进行推导过程,会报错
1 use of 'auto GetNumber(std::size_t pos) const;' before deduction of 'auto'
哈夫曼树 哈夫曼树 题目链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <array> #include <iostream> #include <queue> #include <vector> class Solution { public : int GetWeight (const std::vector<int >& arr) { std::priority_queue<int , std::vector<int >, std::greater<int >> queue; for (auto item : arr) { queue.emplace (item); } int weight = 0 ; int m, n; while (queue.size () > 1 ) { m = queue.top (); queue.pop (); n = queue.top (); queue.pop (); queue.emplace (m + n); weight += m + n; } return weight; } };int main () { Solution solution; int n; while (std::cin >> n) { std::vector<int > arr; arr.resize (n); for (int i = 0 ; i < n; i++) { std::cin >> arr[i]; } int ans = solution.GetWeight (arr); std::cout << ans << std::endl; } return 0 ; }
可以声明数组时直接指定大小std::vector arr(n);,但我觉得resize更好看一些。
二叉树 二叉树遍历 题目链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 #include <iostream> #include <memory> #include <string> class BinaryTree { struct Node { Node (){}; Node (std::shared_ptr<Node> lchild, std::shared_ptr<Node> rchild, char content) : lchild_ (lchild), rchild_ (rchild), content_ (content){}; std::shared_ptr<Node> lchild_; std::shared_ptr<Node> rchild_; char content_; }; using LinkNode = std::shared_ptr<Node>; public : void BuildTree (const std::string& preorder, const std::string& inorder) { root_ = BuildTreeImpl (preorder, inorder); postorder_string_ = "" ; } std::string GetPostorderString () { PostorderVisit (root_); return postorder_string_; } private : LinkNode BuildTreeImpl (const std::string& preorder, const std::string& inorder) ; void PostorderVisit (LinkNode node) ; LinkNode root_; std::string postorder_string_; };BinaryTree::LinkNode BinaryTree::BuildTreeImpl (const std::string& preorder, const std::string& inorder) { if (preorder.empty ()) { return {}; } auto len = preorder.length (); char root_char = preorder[0 ]; auto pos = inorder.find (root_char); auto pre_left = preorder.substr (1 , pos); auto pre_right = preorder.substr (pos + 1 , len - pos - 1 ); auto in_left = inorder.substr (0 , pos); auto in_right = inorder.substr (pos + 1 , len - pos - 1 ); auto lchild = BuildTreeImpl (pre_left, in_left); auto rchild = BuildTreeImpl (pre_right, in_right); auto node = std::make_shared <BinaryTree::Node>(lchild, rchild, root_char); return node; }void BinaryTree::PostorderVisit (LinkNode node) { if (node == nullptr ) { return ; } PostorderVisit (node->lchild_); PostorderVisit (node->rchild_); postorder_string_.push_back (node->content_); }int main () { BinaryTree tree; std::string preorder; std::string inorder; while (std::cin >> preorder >> inorder) { tree.BuildTree (preorder, inorder); std::cout << tree.GetPostorderString () << std::endl; } return 0 ; }
使用智能指针而不使用原始指针构建二叉树
二叉排序树 二叉排序树 题目链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 #include <iostream> #include <memory> #include <vector> class BinaryTree { struct Node { Node (){}; Node (std::shared_ptr<Node> lchild, std::shared_ptr<Node> rchild, char content) : lchild_ (lchild), rchild_ (rchild), content_ (content){}; std::shared_ptr<Node> lchild_; std::shared_ptr<Node> rchild_; int content_; }; using LinkNode = std::shared_ptr<Node>; public : void BuildTree (const std::vector<int >& arr) { for (int item : arr) { Insert (root_, item); } } void PrintTraversalResult () { PreorderVisit (root_); std::cout << std::endl; InorderVisit (root_); std::cout << std::endl; PostorderVisit (root_); std::cout << std::endl; } private : void Insert (LinkNode& node, int num) ; void PreorderVisit (LinkNode node) ; void InorderVisit (LinkNode node) ; void PostorderVisit (LinkNode node) ; LinkNode root_; };void BinaryTree::Insert (LinkNode& node, int num) { if (node == nullptr ) { node = std::make_shared <Node>(nullptr , nullptr , num); return ; } if (node->content_ > num) { Insert (node->lchild_, num); } else if (node->content_ < num) { Insert (node->rchild_, num); } }void BinaryTree::PreorderVisit (LinkNode node) { if (node == nullptr ) { return ; } std::cout << node->content_ << " " ; PreorderVisit (node->lchild_); PreorderVisit (node->rchild_); }void BinaryTree::InorderVisit (LinkNode node) { if (node == nullptr ) { return ; } InorderVisit (node->lchild_); std::cout << node->content_ << " " ; InorderVisit (node->rchild_); }void BinaryTree::PostorderVisit (LinkNode node) { if (node == nullptr ) { return ; } PostorderVisit (node->lchild_); PostorderVisit (node->rchild_); std::cout << node->content_ << " " ; }int main () { int n; while (std::cin >> n) { BinaryTree tree; std::vector<int > arr; arr.resize (n); for (int i = 0 ; i < n; i++) { std::cin >> arr[i]; } tree.BuildTree (arr); tree.PrintTraversalResult (); } return 0 ; }
复制粘贴代码记得检查一下:由于几种遍历方式差不多,我直接复制粘贴然后改一下次序,后面debug了很久才发现函数名没改,同时写成了两个lchild_
No rule to make target ‘binary_sort_tree.cpp’, needed by ‘binary_sort_tree’. Stop. 文件名前有一个空格,导致报错,使用ls命令就能很明显看出
二叉搜索树 题目链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 #include <iostream> #include <memory> #include <string> class BinaryTree { struct Node { Node (){}; Node (std::shared_ptr<Node> lchild, std::shared_ptr<Node> rchild, char content) : lchild_ (lchild), rchild_ (rchild), content_ (content){}; std::shared_ptr<Node> lchild_; std::shared_ptr<Node> rchild_; char content_; }; using LinkNode = std::shared_ptr<Node>; public : void BuildTree (const std::string& arr) { for (char item : arr) { Insert (root_, item); } GenerateTraversalSequence (); } std::string GetCompareSequence () const { return preorder_ + inorder_; } bool Compare (const BinaryTree& tree) { return GetCompareSequence () == tree.GetCompareSequence (); } private : void Insert (LinkNode& node, char num) ; void GenerateTraversalSequence () ; void PreorderVisit (LinkNode node) ; void InorderVisit (LinkNode node) ; void PostorderVisit (LinkNode node) ; LinkNode root_; std::string preorder_; std::string inorder_; std::string postorder_; };void BinaryTree::Insert (LinkNode& node, char num) { if (node == nullptr ) { node = std::make_shared <Node>(nullptr , nullptr , num); return ; } if (node->content_ > num) { Insert (node->lchild_, num); } else if (node->content_ < num) { Insert (node->rchild_, num); } }void BinaryTree::PreorderVisit (LinkNode node) { if (node == nullptr ) { return ; } preorder_.push_back (node->content_); PreorderVisit (node->lchild_); PreorderVisit (node->rchild_); }void BinaryTree::InorderVisit (LinkNode node) { if (node == nullptr ) { return ; } InorderVisit (node->lchild_); inorder_.push_back (node->content_); InorderVisit (node->rchild_); }void BinaryTree::PostorderVisit (LinkNode node) { if (node == nullptr ) { return ; } PostorderVisit (node->lchild_); PostorderVisit (node->rchild_); postorder_.push_back (node->content_); }void BinaryTree::GenerateTraversalSequence () { PreorderVisit (root_); InorderVisit (root_); }int main () { int n; std::string seq; while (std::cin >> n && n != 0 ) { std::cin >> seq; BinaryTree origin_tree; origin_tree.BuildTree (seq); for (int i = 0 ; i < n; i++) { std::cin >> seq; BinaryTree cmp_tree; cmp_tree.BuildTree (seq); bool ans = origin_tree.Compare (cmp_tree); if (ans) { std::cout << "YES" << std::endl; } else { std::cout << "NO" << std::endl; } } } return 0 ; }
注意std::cin与getline函数对换行符的处理的区别
图论一章 并查集 畅通工程 题目链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <iostream> #include <vector> class UnionFind { public : UnionFind (int n) { size_ = n; tree_.resize (n + 1 ); for (int i = 1 ; i <= n; i++) { tree_[i] = i; } } void Union (int p, int q) { int p_root = Find (p); int q_root = Find (q); if (p_root != q_root) { tree_[p_root] = q_root; size_--; } } int GetSize () { return size_; } private : int Find (int p) { if (tree_[p] == p) { return p; } else { int root = Find (tree_[p]); tree_[p] = root; return root; } } int size_; std::vector<int > tree_; };int main () { int n, m; while (std::cin >> n && n != 0 ) { std::cin >> m; UnionFind tool (n) ; int p, q; for (int i = 0 ; i < m; i++) { std::cin >> p >> q; tool.Union (p, q); } std::cout << tool.GetSize () - 1 << std::endl; } return 0 ; }
这个与之前写的差不多。。。
最小生成树 还是畅通工程 题目链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 #include <algorithm> #include <iostream> #include <vector> class UnionFind { public : struct Edge { int from_; int to_; int cost_; }; UnionFind (int n, std::vector<Edge>&& edge) : size_ (n), sum_ (0 ), edge_ (edge) { tree_.resize (n + 1 ); for (int i = 1 ; i <= n; i++) { tree_[i] = i; } std::sort (edge_.begin (), edge_.end (), [](const Edge& e1, const Edge& e2) { return e1.cost_ < e2.cost_; }); } void Union (Edge e) { int p_root = Find (e.from_); int q_root = Find (e.to_); if (p_root != q_root) { tree_[p_root] = q_root; size_--; sum_ += e.cost_; } } int GetMinSpanningTree () { for (const auto & e : edge_) { Union (e); if (size_ == 0 ) { return sum_; } } return sum_; } private : int Find (int p) { if (tree_[p] == p) { return p; } else { int root = Find (tree_[p]); tree_[p] = root; return root; } } int size_; int sum_; std::vector<int > tree_; std::vector<Edge> edge_; };int main () { int n; while (std::cin >> n && n != 0 ) { int edge_num = n * (n - 1 ) / 2 ; std::vector<UnionFind::Edge> edges; edges.resize (edge_num); for (int i = 0 ; i < edge_num; i++) { std::cin >> edges[i].from_ >> edges[i].to_ >> edges[i].cost_; } UnionFind tool (n, std::move(edges)) ; std::cout << tool.GetMinSpanningTree () << std::endl; } return 0 ; }
我不怎么喜欢在类方法中接受用户输入,故在main方法接受用户输入再传入,有些冗余。
Freckles 题目链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 #include <algorithm> #include <cmath> #include <iostream> #include <vector> class UnionFind { public : struct Dot { double x_; double y_; }; struct Edge { int from_; int to_; double cost_; Edge (int from, int to, double cost) : from_ (from), to_ (to), cost_ (cost) {} }; UnionFind (int n, const std::vector<Dot>& dots) : size_ (n), sum_ (0 ) { tree_.resize (n + 1 ); for (int i = 1 ; i <= n; i++) { tree_[i] = i; } edge_.reserve (n * (n - 1 ) / 2 ); double cost; for (int i = 0 ; i < n - 1 ; i++) { for (int j = i + 1 ; j < n; j++) { cost = GetDistance (dots[i], dots[j]); edge_.emplace_back (Edge{i, j, cost}); } } std::sort (edge_.begin (), edge_.end (), [](const Edge& e1, const Edge& e2) { return e1.cost_ < e2.cost_; }); } void Union (Edge e) { int p_root = Find (e.from_); int q_root = Find (e.to_); if (p_root != q_root) { tree_[p_root] = q_root; size_--; sum_ += e.cost_; } } double GetMinSpanningTree () { for (const auto & e : edge_) { Union (e); if (size_ == 0 ) { return sum_; } } return sum_; } private : int Find (int p) { if (tree_[p] == p) { return p; } else { int root = Find (tree_[p]); tree_[p] = root; return root; } } double GetDistance (const Dot& lhs, const Dot& rhs) { double res = (lhs.x_ - rhs.x_) * (lhs.x_ - rhs.x_) + (lhs.y_ - rhs.y_) * (lhs.y_ - rhs.y_); return sqrt (res); } int size_; double sum_; std::vector<int > tree_; std::vector<Edge> edge_; };int main () { int n; while (std::cin >> n && n != 0 ) { std::vector<UnionFind::Dot> dots; dots.resize (n); for (int i = 0 ; i < n; i++) { std::cin >> dots[i].x_ >> dots[i].y_; } UnionFind tool (n, dots) ; double weight = tool.GetMinSpanningTree (); printf ("%.2f" , weight); } return 0 ; }
全是重复的代码。。。
最短路径 最短路 题目链接 需注册才能提交代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 #include <iostream> #include <vector> const int kInf = -1 ;const int kMax = 1 << 30 ;class Solution { public : int GetShortestPath (const std::vector<std::vector<int >>& graph) { return GetShortestPathUseDijkstraForMatrix (graph); } private : struct Edge { int to_; int cost_; Edge (int to, int cost) : to_ (to), cost_ (cost) {} }; int GetShortestPathUseFloyd (const std::vector<std::vector<int >>& graph) { std::vector<std::vector<int >> ans = graph; int n = static_cast <int >(ans.size () - 1 ); for (int k = 1 ; k <= n; k++) { for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= n; j++) { if (ans[i][k] == kInf || ans[k][j] == kInf) { continue ; } if (ans[i][j] == kInf || ans[i][j] > ans[i][k] + ans[k][j]) { ans[i][j] = ans[i][k] + ans[k][j]; } } } } return ans[1 ][n]; } int GetShortestPathUseDijkstraForMatrix (const std::vector<std::vector<int >>& graph) { int n = static_cast <int >(graph.size () - 1 ); std::vector<bool > mark (n + 1 , false ) ; std::vector<int > dist (n + 1 , kInf) ; int new_dist; int min_dist; int v = 1 ; dist[1 ] = 0 ; mark[1 ] = true ; for (int times = 0 ; times <= n; times++) { for (int j = 1 ; j <= n; j++) { if (mark[j] || graph[v][j] == kInf) { continue ; } new_dist = dist[v] + graph[v][j]; if (dist[j] == kInf || dist[j] > new_dist) { dist[j] = new_dist; } } min_dist = kMax; for (int j = 1 ; j <= n; j++) { if (mark[j] || dist[j] == kInf) { continue ; } if (min_dist > dist[j]) { min_dist = dist[j]; v = j; } } mark[v] = true ; if (v == n) { break ; } } return dist[n]; } int GetShortestPathUseDijkstraForList (const std::vector<std::vector<int >>& graph) { int n = static_cast <int >(graph.size () - 1 ); std::vector<std::vector<Edge>> edges; std::vector<bool > mark (n + 1 , false ) ; std::vector<int > dist (n + 1 , kInf) ; edges.resize (n + 1 ); for (int i = 1 ; i <= n - 1 ; i++) { for (int j = i + 1 ; j <= n; j++) { if (graph[i][j] != kInf) { edges[i].emplace_back (Edge (j, graph[i][j])); edges[j].emplace_back (Edge (i, graph[i][j])); } } } int new_dist; int min_dist; int edges_size; int to; int cost; int v = 1 ; dist[1 ] = 0 ; mark[1 ] = true ; for (int times = 0 ; times <= n; times++) { edges_size = static_cast <int >(edges[v].size ()); for (int j = 0 ; j < edges_size; j++) { to = edges[v][j].to_; cost = edges[v][j].cost_; if (mark[to]) { continue ; } new_dist = dist[v] + cost; if (dist[to] == kInf || dist[to] > new_dist) { dist[to] = new_dist; } } min_dist = kMax; for (int j = 1 ; j <= n; j++) { if (mark[j] || dist[j] == kInf) { continue ; } if (min_dist > dist[j]) { min_dist = dist[j]; v = j; } } mark[v] = true ; if (v == n) { break ; } } return dist[n]; } };int main () { Solution solution; int n, m; int p, q, cost; while (std::cin >> n >> m) { if (n == 0 && m == 0 ) { break ; } std::vector<std::vector<int >> graph (n + 1 , std::vector <int >(n + 1 , kInf)); for (int i = 0 ; i < m; i++) { std::cin >> p >> q >> cost; if (graph[p][q] == kInf || graph[p][q] > cost) { graph[p][q] = cost; graph[q][p] = cost; } } int time = solution.GetShortestPath (graph); std::cout << time << std::endl; } return 0 ; }
使用Floyd与Dijkstra算法分别求解最短路径,我之前写的代码中没有考虑重复边,所以是错的。很容易看出代码的执行效率是比较低的,但我主要追求的是好看,也就无所谓了
最短路径问题 题目链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 #include <iostream> #include <vector> #include <tuple> const int kInf = -1 ;const int kMax = 1 << 30 ;class Solution { public : struct Edge { int to_; int dist_; int cost_; Edge (int to, int dist, int cost) : to_ (to), dist_ (dist), cost_ (cost) {} }; auto GetShortestPath (const std::vector<std::vector<Edge>>& edges, int start, int end) { int n = static_cast <int >(edges.size () - 1 ); std::vector<bool > mark (n + 1 , false ) ; std::vector<int > dist_matrix (n + 1 , kInf) ; std::vector<int > cost_matrix (n + 1 , kInf) ; int new_dist; int new_cost; int min_dist; int min_cost; int edges_size; int to; int cost; int dist; int v = start; dist_matrix[start] = 0 ; cost_matrix[start] = 0 ; mark[start] = true ; for (int times = 0 ; times <= n; times++) { edges_size = static_cast <int >(edges[v].size ()); for (int j = 0 ; j < edges_size; j++) { to = edges[v][j].to_; dist = edges[v][j].dist_; cost = edges[v][j].cost_; if (mark[to]) { continue ; } new_dist = dist_matrix[v] + dist; new_cost = cost_matrix[v] + cost; if (dist_matrix[to] == kInf || dist_matrix[to] > new_dist || (dist_matrix[to] == new_dist && cost_matrix[to] > new_cost)) { dist_matrix[to] = new_dist; cost_matrix[to] = new_cost; } } min_dist = kMax; min_cost = kMax; for (int j = 1 ; j <= n; j++) { if (mark[j] || dist_matrix[j] == kInf) { continue ; } if (min_dist > dist_matrix[j] || (min_dist == dist_matrix[j] && min_cost > cost_matrix[j])) { min_dist = dist_matrix[j]; min_cost = cost_matrix[j]; v = j; } } mark[v] = true ; if (v == end) { break ; } } return std::make_tuple (dist_matrix[end], cost_matrix[end]); } };int main () { Solution solution; int n, m; int p, q, dist, cost; int start, end; std::cin >> n >> m; std::vector<std::vector<Solution::Edge>> edges; edges.resize (n + 1 ); for (int i = 0 ; i < m; i++) { std::cin >> p >> q >> dist >> cost; edges[p].emplace_back (Solution::Edge (q, dist, cost)); edges[q].emplace_back (Solution::Edge (p, dist, cost)); } std::cin >> start >> end; auto [min_dist, min_cost] = solution.GetShortestPath (edges, start, end); std::cout << min_dist << " " << min_cost << std::endl; return 0 ; }
距离为一个抽象集合而非特定的变量
拓扑排序 Leagal or Not 没找到相应的oj题,不一定对
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 #include <iostream> #include <queue> #include <vector> class Solution { public : bool IsLeagal (const std::vector<std::vector<int >>& edges, std::vector<int >& indegree) { std::queue<int > zero_indegree_nodes; int n = static_cast <int >(indegree.size ()); for (int i = 0 ; i < n; i++) { if (indegree[i] == 0 ) { zero_indegree_nodes.emplace (i); } } int node_number = 0 ; int node; int edge_size; int to; while (!zero_indegree_nodes.empty ()) { node = zero_indegree_nodes.front (); zero_indegree_nodes.pop (); node_number++; edge_size = static_cast <int >(edges[node].size ()); for (int i = 0 ; i < edge_size; i++) { to = edges[node][i]; indegree[to]--; if (indegree[to] == 0 ) { zero_indegree_nodes.emplace (to); } } } if (node_number == n) { return true ; } return false ; } };int main () { Solution solution; int m, n; int x, y; while (std::cin >> n >> m && n != 0 ) { std::vector<std::vector<int >> edges; edges.resize (n); std::vector<int > indegree (n, 0 ) ; for (int i = 0 ; i < m; i++) { std::cin >> x >> y; edges[x].emplace_back (y); indegree[y]++; } bool ans = solution.IsLeagal (edges, indegree); if (ans) { std::cout << "YES" << std::endl; } else { std::cout << "NO" << std::endl; } } }
动态规划一章 递推求解 N 阶楼梯上楼问题 题目链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <iostream> class Solution { public : int GetUpstairsWay (int n) { if (n <= 2 ) { return n; } int f1 = 2 ; int f2 = 1 ; int tmp; for (int i = 3 ; i < n; i++) { tmp = f1; f1 = f1 + f2; f2 = tmp; } return f1 + f2; } };int main () { Solution solution; int n; int ans; while (std::cin >> n) { ans = solution.GetUpstairsWay (n); std::cout << ans << std::endl; } }
背包 采药 题目链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include <iostream> #include <vector> class Solution { public : struct Medicine { int time_; int value_; Medicine (int time, int value) : time_ (time), value_ (value) {} }; int GetMaxValue (const std::vector<Medicine>& list, int total_time) { int n = static_cast <int >(list.size ()); std::vector<int > dp (total_time + 1 , 0 ) ; for (int i = 0 ; i < n; i++) { for (int j = total_time; j >= list[i].time_; j--) { dp[j] = std::max (dp[j - list[i].time_] + list[i].value_, dp[j]); } } return dp[total_time]; } };int main () { Solution solution; int T, M; int time, value; while (std::cin >> T >> M) { std::vector<Solution::Medicine> list; for (int i = 0 ; i < M; i++) { std::cin >> time >> value; list.emplace_back (Solution::Medicine (time, value)); } int ans = solution.GetMaxValue (list, T); std::cout << ans << std::endl; } }
Piggy-Bank 没找到相应的题目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 #include <iostream> #include <vector> const int kInf = -1 ;class Solution { public : struct Coin { int value_; int weight_; Coin (int value, int weight) : value_ (value), weight_ (weight) {} }; int GetMinAmount (const std::vector<Coin>& coins, int total_weight) { int n = static_cast <int >(coins.size ()); std::vector<int > dp (total_weight + 1 , kInf) ; dp[0 ] = 0 ; for (int i = 0 ; i < n; i++) { for (int j = coins[i].weight_; j <= total_weight; j++) { if (dp[j - coins[i].weight_] != kInf) { if (dp[j] != kInf) { dp[j] = std::min (dp[j - coins[i].weight_] + coins[i].value_, dp[j]); } else { dp[j] = dp[j - coins[i].weight_] + coins[i].value_; } } } } return dp[total_weight]; } };int main () { Solution solution; int T; int E, F; int N; int P, W; std::cin >> T; while (T--) { std::cin >> E >> F >> N; std::vector<Solution::Coin> coins; coins.reserve (N); for (int i = 0 ; i < N; i++) { std::cin >> P >> W; coins.emplace_back (Solution::Coin (P, W)); } int min_value = solution.GetMinAmount (coins, F - E); if (min_value == kInf) { std::cout << "This is impossible." << std::endl; } else { std::cout << "The minimum amount of money in the piggy-bank is " << min_value << "." << std::endl; } } }
珍惜现在,感恩生活 没找到题目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 #include <iostream> #include <vector> class Solution { public : struct Rice { int price_; int weight_; Rice (int price, int weight) : price_ (price), weight_ (weight) {} }; int GetMaxWeight (const std::vector<Rice>& rices, int money) { int n = static_cast <int >(rices.size ()); std::vector<int > dp (money + 1 , 0 ) ; for (int i = 0 ; i < n; i++) { for (int j = money; j >= rices[i].price_; j--) { dp[j] = std::max (dp[j - rices[i].price_] + rices[i].weight_, dp[j]); } } return dp[money]; } };int main () { Solution solution; int C; int n, m; int p, h, c; std::cin >> C; while (C--) { std::cin >> n >> m; std::vector<Solution::Rice> rices; rices.reserve (5 * m); for (int i = 0 ; i < m; i++) { std::cin >> p >> h >> c; int k = 1 ; while (c - k > 0 ) { rices.emplace_back (Solution::Rice (p * k, h * k)); c -= k; k *= 2 ; } if (c != 0 ) { rices.emplace_back (Solution::Rice (p * c, h * c)); } } int max_weight = solution.GetMaxWeight (rices, n); std::cout << max_weight << std::endl; } }
二进制拆分相关博客:多重背包 证明二进制拆分n[i]得到的数能够组成0~n[i]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 一个数n拆成小于它的所有二的次方的和(指数递增的)加上剩下一个数。实际上就是将这个数的二进制的每一位选或者不选就可以组成一个范围在0~n的数 举个例子:13可以拆成 2^0 、 2^1 、 2^2、和 6(6是剩下的那个数),也就是拆分成 1 2 4 6,那么通过选择这4个数的就可以表示0~13的任意数。 如: 0:一个都不选。 1:选1; 2:选2; 3:选1和2; 4: 选4; 5:选1和4; 6:选2和4; 7:选1和2和4; 8:选2和6; 9:选1和2和6; 10: 选4和6; 11:选1和4和6; 12:选2和4和6; 13:全选;