失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 【操作指导 | 代码实现】挑战程序设计竞赛2:算法和数据结构

【操作指导 | 代码实现】挑战程序设计竞赛2:算法和数据结构

时间:2020-08-31 23:59:57

相关推荐

【操作指导 | 代码实现】挑战程序设计竞赛2:算法和数据结构

书籍封面

第一章 前言

1. 本人衷心建议

~~~~~~ 如果你是一位初学者,我指的是你只会基本的 C/C++ 编程,即使编的很烂,这本书对于你算法和数据结构的提升非常有帮助,所涉及的每一个算法案例都非常经典,且有非常细致的讲解,本人强烈推荐你理解好每一道题的细节。

~~~~~~ 如果你具备一定的算法与数据结构能力,本书的内容依然很适合你,你可以有针对性的补充相应章节的内容,一定会有意想不到的收获。

~~~~~~ 当你看到如此多的章节,每个章节还有如此多的内容时,一定不要被吓到,当本人对算法与数据结构一头雾水时,也是一步步算法过来的,这本书的学习大概花费了我近一个月的时间,所以你不必想着马上就可以看完很多,知识需要慢慢消化,Good luck !

注:算法涉及的题目如何在网上搜索见下文,特意强调,无需翻墙。

2. 本书涉及的所有题目以及对应的编号

3. AOJ 使用方法《挑战程序设计竞赛》

网址

https://onlinejudge.u-aizu.ac.jp/home

注册

点右上角 Guest ==> Sign Up

注册完成后点击 submit

查找题目

1.点击网站上方 Challenge ==> Search

2.直接搜索题目

3. 或者根据上面 2 中题目对应的编号进行查找

点击 Volumes ,因为题号是 0202,前两位是 02,所以选 Volume2,然后找到对应编号即可

做题

进去之后选择语言,编写代码,并提交即可。当你看到全是日语的时候,不要惊慌,你完全可以看懂题,毕竟每道题的中文翻译都在本文中了…

提交后往下翻查看状态

用 virtual judge 做 AOJ 的题目

一个非常便捷的网站:/problem#OJId=Aizu&probNum=&title=&source=&category=all

首先进行账号注册

点进去做题就可以了

第二章 算法与复杂度

2.4 算法的效率

2.4.1 复杂度的评估

2.4.2 大 O 表示法

2.4.3 复杂度的比较

第三章 初等排序

3.1 挑战问题之前——排序

3.2 插入排序法

题解

代码实现

#include<iostream>#include<cstdio>#include<cmath>using namespace std;// 打印数列Avoid print(int A[],int n) {for (int i = 0; i < n; i++)printf("%d%c", A[i], i == n - 1 ? '\n' : ' ');}// 插入排序法void insertsort(int A[], int n) {// 从第二个开始,往前找比当前的小的值,// 比当前值大的就往后移,知道找到小于等于A[i]的for (int i = 1; i < n; i++) {int j = i - 1;int v = A[i];while (j >= 0 && A[j] > v) {A[j + 1] = A[j];j--;}A[j + 1] = v;print(A, n);}}int main() {int n, A[110];scanf("%d", &n);for (int i = 0; i < n; i++)scanf("%d", &A[i]);print(A, n);insertsort(A, n);return 0;}

3.3 冒泡排序法

题解

代码实现

#include<iostream>#include<cstdio>#include<cmath>using namespace std;// 冒泡排序法int bubbleSort(int A[], int n) {int cnt = 0;// 标记是否需要继续冒泡int flag = 1;for (int i = 0; flag; i++) {flag = 0;for (int j = n - 1; j >= i + 1; j--) {// 交换两个相邻的元素if (A[j] < A[j - 1]) {swap(A[j], A[j - 1]);flag = 1;cnt++;}}}return cnt;}int main() {int n, A[110];scanf("%d", &n);for (int i = 0; i < n; i++)scanf("%d", &A[i]);int cnt = bubbleSort(A, n);for (int i = 0; i < n; i++)printf("%d%c", A[i], i == n - 1 ? '\n' : ' ');printf("%d\n", cnt);return 0;}

3.4 选择排序法

题解

代码实现

#include<iostream>#include<cstdio>#include<cmath>using namespace std;// 选择排序法int selectionSort(int A[], int n) {int cnt = 0;for (int i = 0; i < n; i++) {int minj = i;for (int j = i; j < n; j++) {if (A[j] < A[minj])minj = j;}if (i != minj)swap(A[i], A[minj]), cnt++;}return cnt;}int main() {int n, A[110];scanf("%d", &n);for (int i = 0; i < n; i++)scanf("%d", &A[i]);int cnt = selectionSort(A, n);for (int i = 0; i < n; i++)printf("%d%c", A[i], i == n - 1 ? '\n' : ' ');printf("%d\n", cnt);return 0;}

3.6 希尔排序法

题解

代码实现

#include<iostream>#include<cstdio>#include<vector>using namespace std;//g数组vector<int>G;long long cnt;int A[1000000 + 10];// 间隔为g的插入排序void insertionSort(int A[], int n, int g) {for (int i = g; i < n; i++) {int v = A[i];int j = i - g;while (j >= 0 && A[j] > v) {A[j + g] = A[j];j -= g;cnt++;}A[j + g] = v;}}//希尔排序void shellsort(int A[], int n) {for (int i = G.size() - 1; i >= 0; i--) {insertionSort(A, n, G[i]);}}// 生成g数组void getArray(int n) {for (int h = 1; h <= n;) {G.push_back(h);h = 3 * h + 1;}}int main() {int n;scanf("%d", &n);for (int i = 0; i < n; i++)scanf("%d", &A[i]);getArray(n);shellsort(A,n);int len = G.size();printf("%d\n", len);for (int i = len - 1; i >= 0; i--)printf("%d%c", G[i], i == 0 ? '\n' : ' ');printf("%lld\n", cnt);for (int i = 0; i < n; i++)printf("%d\n", A[i]);return 0;}

第四章 数据结构

4.1 挑战问题之前一一什么是数据结构

4.2 栈

题解

代码实现

stack1

/*实现栈的功能*/#include<iostream>#include<cstdio>using namespace std;// 实现栈的功能// top是指向栈顶的指针, s是实现栈结构的数组int top, S[1000];// 将x压入栈的操作void push(int x) {// top加1之后将元素插入到top所指的位置S[++top] = x;}// 将栈顶元素返回并删除int pop() {top--;return S[top + 1];}// 字符转数字int CharToInt(char s[]) {int ans = 0, i = 0;while (s[i] != '\0') {ans = ans * 10 + s[i] - '0';i++;}return ans;}int main() {char s[1000];int a, b;// 清空栈top = 0; while(scanf("%s",s)!=EOF){if (s[0] == '+') {b = pop();a = pop();push(a + b);}else if (s[0] == '-') {b = pop(); a = pop();push(a - b);}else if (s[0] == '*') {b = pop(); a = pop();push(a * b);}else {push(CharToInt(s));}}printf("%d\n",pop());return 0;}

stack2

/*利用STL的stack类*/#include<iostream>#include<cstdio>#include<stack>using namespace std;// 字符转数字int CharToInt(char s[]) {int ans = 0, i = 0;while (s[i] != '\0') {ans = ans * 10 + s[i] - '0';i++;}return ans;}int main() {char s[1000];int a, b;stack<int> S;while(scanf("%s",s)!=EOF){if (s[0] == '+') {b = S.top(); S.pop();a = S.top(); S.pop();S.push(a + b);}else if (s[0] == '-') {b = S.top(); S.pop();a = S.top(); S.pop();S.push(a - b);}else if (s[0] == '*') {b = S.top(); S.pop();a = S.top(); S.pop();S.push(a * b);}else {S.push(CharToInt(s));}}printf("%d\n", S.top());return 0;}

4.3 队列

题解

代码实现

queue1

/*实现队列功能*/#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int maxx = 100000 + 10;struct task {// 任务的名字和耗费的时间char name[100];int t;};task Queue[maxx];// 指向队头和队尾的指针int head, tail;// 判断循环队列是否已满bool isFull() {return head == (tail + 1) % maxx;}// 判断循环队列是否为空bool isEmpty() {return head == tail;}// 将元素x添加到队列的末尾void enqueue(task x) {Queue[tail] = x;// 循环队列tail = (tail + 1) % maxx;}// 返回队头元素并删除task dequeue() {task x = Queue[head];// 循环队列head = (head + 1) % maxx;return x;}int main() {int n, q;scanf("%d %d", &n, &q);for (int i = 0; i < n; i++) {scanf("%s %d", Queue[i].name, &Queue[i].t);}// 当前已经有n个元素head = 0; tail = n;// 当前时间int nowtime = 0;while (!isEmpty()) {// 取出队头task u = dequeue();// 执行时间片 p 和 所需要时间u.tint c = min(q, u.t);// 任务执行了 c msu.t -= c;// 当前时间加上c msnowtime += c;// 任务还没做完,加入到队尾if (u.t > 0) {enqueue(u);}else {// 任务已经完成,打印出结果printf("%s %d\n", u.name, nowtime);}}return 0;}

queue2

/*利用STL的queue类*/#include<iostream>#include<cstdio>#include<algorithm>#include<queue>using namespace std;const int maxx = 100000 + 10;struct task {// 任务的名字和耗费的时间char name[100];int t;};queue<task> Queue;int main() {int n, q;scanf("%d %d", &n, &q);for (int i = 0; i < n; i++) {task t;scanf("%s %d", t.name, &t.t);Queue.push(t);}// 当前时间int nowtime = 0;while (!Queue.empty()) {// 取出队头task u = Queue.front();Queue.pop();// 执行时间片 p 和 所需要时间u.tint c = min(q, u.t);// 任务执行了 c msu.t -= c;// 当前时间加上c msnowtime += c;// 任务还没做完,加入到队尾if (u.t > 0) {Queue.push(u);}else {// 任务已经完成,打印出结果printf("%s %d\n", u.name, nowtime);}}return 0;}

4.4 链 表

题解

代码实现

List1

/*实现双向链表功能*/#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>using namespace std;const int maxx = 100000 + 10;struct Node {int key;Node *prev, *next;};Node *nil;// 链表初始化void init() {nil = (Node *)malloc(sizeof(Node));//C++ nil = new Node();nil->next = nil;nil->prev = nil;}// 从链表搜索出值为key的结点 O(n)Node* listSearch(int key) {// 从链表头结点开始访问Node *cur = nil->next;while (cur != nil && cur->key != key) {cur = cur->next;}return cur;}// 打印链表void printList() {Node *cur = nil->next;int flag = 0;while (cur != nil) {if (flag++ > 0)printf(" ");printf("%d", cur->key);cur = cur->next;}printf("\n");}// 删除结点tvoid deleteNode(Node *t) {// t为头结点不做处理if (t == nil)return;t->prev->next = t->next;t->next->prev = t->prev;free(t);//C++ delete(t);}// 删除头结点void deleteFirst() {deleteNode(nil->next);}// 删除尾结点void deleteLast() {deleteNode(nil->prev);}// 删除指定的key O(n)void deleteKey(int key) {deleteNode(listSearch(key));}// 在链表头部添加元素keyvoid insert(int key) {Node *x = (Node *)malloc(sizeof(Node));//C++ Node *x = new Node();x->key = key;x->next = nil->next;nil->next->prev = x;nil->next = x;x->prev = nil;}int main() {int n, key, size = 0;char op[20];scanf("%d", &n);getchar();// 初始化链表init();for (int i = 0; i < n; i++) {scanf("%s %d", op, &key);if (op[0] == 'i') {insert(key);size++;}else {if (strlen(op) > 6) {if (op[6] == 'F') {//删除头结点deleteFirst();}else {//删除尾结点deleteLast();}}else {//删除结点deleteKey(key);}size--;}}printList();return 0;}

List2

/*利用STL的list类*/#include<iostream>#include<cstdio>#include<cstring>#include<list>using namespace std;int main() {int n, key;char op[20];list<int> List;scanf("%d", &n);getchar();for (int i = 0; i < n; i++) {scanf("%s %d", op, &key);if (op[0] == 'i') {List.push_front(key);}else {if (strlen(op) > 6) {if (op[6] == 'F') {//删除头结点List.pop_front();}else {//删除尾结点List.pop_back();}}else {//删除结点for (list<int>::iterator it = List.begin(); it != List.end(); it++) {if (*it == key) {List.erase(it);break;}}}}}int flag = 0;for (list<int>::iterator it = List.begin(); it != List.end(); it++) {if (flag != 0)printf(" ");flag++;printf("%d", (*it));}printf("\n");return 0;}

4.5 标准库的数据结构

4.5.2 stack

4.5.3 queue

4.5.4 vector

4.5.5 list

第五章 搜索

5.1 挑战问题之前一搜索

5.2 线性搜索

题解

代码实现

#include<iostream>#include<cstdio>using namespace std;// 线性搜索bool LinearSearch(int A[], int n, int key) {// 将key设置为数列最后一项A[n] = key;int i = 0;while (A[i] != key)i++;// 如果i不是n,则代表在原来的数列中找到key,// 否则代表原来数列中没有key,找到的是刚才插入到最后的元素return i != n;}int main() {int n, q, key;int sum = 0;int A[10000 + 10];scanf("%d", &n);for (int i = 0; i < n; i++)scanf("%d", &A[i]);scanf("%d", &q);for (int i = 0; i < q; i++) {scanf("%d", &key);if (LinearSearch(A, n, key))sum++;}printf("%d\n", sum);}

5.3 二分搜索

题解

代码实现

方式一

/*实现二分搜索*/#include<iostream>#include<cstdio>using namespace std;// 二分搜索bool BinarySearch(int A[], int n, int key) {int left = 0 , right = n, mid;while (left < right) {mid = (left + right) / 2;if (key == A[mid])return true;if(key > A[mid])left = mid + 1;if (key < A[mid])right = mid;}return false;}int main() {int n, q, key;int sum = 0;int A[100000 + 10];scanf("%d", &n);for (int i = 0; i < n; i++)scanf("%d", &A[i]);scanf("%d", &q);for (int i = 0; i < q; i++) {scanf("%d", &key);if (BinarySearch(A, n, key))sum++;}printf("%d\n", sum);}

方式二

/*利用STL的binary_search*/#include<iostream>#include<cstdio>#include<algorithm>using namespace std;int main() {int n, q, key;int sum = 0;int A[100000 + 10];scanf("%d", &n);for (int i = 0; i < n; i++)scanf("%d", &A[i]);scanf("%d", &q);for (int i = 0; i < q; i++) {scanf("%d", &key);if (binary_search(A, A + n, key))sum++;}printf("%d\n", sum);}

5.4 散列法

题解

代码实现

#include<iostream>#include<cstdio>#include<cstring>using namespace std;typedef long long LL;const LL maxx = 1000000 + 10;char H[maxx][15];// 将字符转换为数值LL CharToInt(char ch) {if (ch == 'A') return 1;if (ch == 'C') return 2;if (ch == 'G') return 3;if (ch == 'T') return 4;return 0;}// 将字符串转成数值并生成keylong long getKey(char str[]) {LL sum = 0, p = 1;LL len = strlen(str);for (long long int i = 0; i < len; i++) {sum += p * CharToInt(str[i]);p *= 5;}return sum;}LL h1(LL key) {return key % maxx;}LL h2(LL key) {return 1 + (key % (maxx - 1));}// find 操作bool find(char str[]) {LL key, h;key = getKey(str);for (LL i = 0;; i++) {h = (h1(key) + i * h2(key)) % maxx;//找到keyif (strcmp(H[h], str) == 0) return true;// key不存在else if (strlen(H[h]) == 0) return false;}return false;}// insert操作void insert(char str[]) {LL key, h;key = getKey(str);for (LL i = 0;; i++) {h = (h1(key) + i * h2(key)) % maxx;//找到keyif (strcmp(H[h], str) == 0) return ;// key不存在else if (strlen(H[h]) == 0) {// 插入strcpy(H[h], str);return ;}}}int main() {int n, q, key;char str[20], op[20];for (int i = 0; i < maxx; i++)H[i][0] = '\0';scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%s %s", op, str);if (op[0] == 'i')insert(str);else {if (find(str))printf("yes\n");elseprintf("no\n");}}return 0;}

5.5 借助标准库搜索

5.5.1 迭 代 器

5.5.2 lower bound

5.6 搜索的应用——计算最优解

这是一个稍微有些难度的挑战题。如果各位觉得太难可以暂时跳过,等具备一定实力后再冋过头来挑战。

题解

代码实现

#include<iostream>#include<cstdio>#include<cstring>using namespace std;typedef long long LL;LL A[100000 + 10];int n, k;//模拟装货过程bool check(LL P) {int cnt = k;for (int i = 0; i < n; ) {LL t = P;cnt--;// 卡车已经用完,证明卡车当前最大装载量不能装完货物if (cnt < 0)return false;while (i < n && t >= 0) {// 剩余重量可以装上当前货物if (t >= A[i])t -= A[i],i++;//装不下则用下一辆卡车去装if (t < A[i])break;}}return true;}// 二分找出P的最小值LL BinarySearch(LL sum) {LL left = 0, right = sum;LL mid;while (left + 1 < right) {mid = (left + right) / 2;//可以装好货物if (check(mid))right = mid;elseleft = mid;}return right;}int main() {LL sum = 0;scanf("%d %d", &n, &k);for (int i = 0; i < n; i++) {scanf("%lld", &A[i]);sum += A[i];}LL P = BinarySearch(sum);printf("%lld\n", P);return 0;}

第六章 递归和分治法

6.1 挑战问题之前一递归与分治

6.2 穷 举 搜 索

题解

代码实现

#include<iostream>#include<cstdio>using namespace std;int n, A[30];// 递归穷举bool solve(int i, int m) {// 已经找到得到m的组合方式if (m == 0)return true;// 已经穷举过A的全部元素了if (i >= n)return false;// 分别穷举 不选A[i] 和 选择A[i]的情况return solve(i + 1, m) || solve(i + 1, m - A[i]);}int main(){int t, M;scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%d", &A[i]);}scanf("%d", &t);for (int i = 0; i < t; i++) {scanf("%d", &M);if (solve(0, M))printf("yes\n");elseprintf("no\n");}return 0;}

6.3 科 赫 曲 线

题解

代码实现

#include<iostream>#include<cstdio>#include<cmath>using namespace std;const double PI = acos(-1.0);struct Point{double x,y;};void koch(int n, Point a, Point b) {// 递归结束if (n == 0)return;// 三等分点s,t ,(u 是 s,t 上方的点)Point s, t, u;// 角度从度转成弧度double th = PI * 60.0 / 180.0;s.x = (2.0 * a.x + 1.0 * b.x) / 3.0;s.y = (2.0 * a.y + 1.0 * b.y) / 3.0;t.x = (1.0 * a.x + 2.0 * b.x) / 3.0;t.y = (1.0 * a.y + 2.0 * b.y) / 3.0;u.x = (t.x - s.x) * cos(th) - (t.y - s.y) * sin(th) + s.x;u.y = (t.x - s.x) * sin(th) + (t.y - s.y) * cos(th) + s.y;koch(n - 1, a, s);printf("%.8lf %.8lf\n", s.x, s.y);koch(n - 1, s, u);printf("%.8lf %.8lf\n", u.x, u.y);koch(n - 1, u, t);printf("%.8lf %.8lf\n", t.x, t.y);koch(n - 1, t, b);}int main(){Point a, b;int n;scanf("%d", &n);// 初始化a.x = a.y = 0;b.x = 100, b.y = 0;printf("%.8lf %.8lf\n", a.x, a.y);koch(n, a, b);printf("%.8lf %.8lf\n", b.x, b.y);return 0;}

第八章 树

8.2 有根树的表达

题解

代码实现

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>using namespace std;const int MAX = 100005;const int NIL = -1;struct Node {int p, l, r;};Node Tree[MAX];int n, Depth[MAX];void print(int u) {printf("node %d: ", u);printf("parent = %d, ", Tree[u].p);printf("depth = %d, ", Depth[u]);if (Tree[u].p == NIL)printf("root, ");else if (Tree[u].l == NIL)printf("leaf, ");elseprintf("internal node, ");printf("[");// 从子结点的最左边开始遍历int c = Tree[u].l;while (c != NIL) {printf("%d", c);if (Tree[c].r != NIL)printf(", ");// 跳到右侧紧邻的兄弟结点c = Tree[c].r;}printf("]\n");}// 递归得求深度void rec(int u, int depth) {Depth[u] = depth;if (Tree[u].r != NIL) // 右侧兄弟设置为相同深度rec(Tree[u].r, depth);if (Tree[u].l != NIL) // 最左侧子结点的深度设置为自己的深度 + 1rec(Tree[u].l, depth + 1);}int main() {int n;scanf("%d", &n);for (int i = 0; i < n; i++) {Tree[i].p = Tree[i].l = Tree[i].r = NIL;}int v, num, c, l, root;for (int i = 0; i < n; i++) {// v是当前结点值 ,num是v结点的子结点数 scanf("%d %d", &v, &num);for (int j = 0; j < num; j++) {scanf("%d", &c);//设置最左侧结点 和 紧邻右侧兄弟结点// l记录的是上一个结点,将当前的结点设置为l的紧邻右侧结点if (j == 0)Tree[v].l = c;elseTree[l].r = c;l = c;// 设置父结点Tree[c].p = v;}}// 找出根结点for (int i = 0; i < n; i++) {if (Tree[i].p == NIL)root = i;}rec(root, 0);for (int i = 0; i < n; i++)print(i);return 0;}

8.3 二叉树的表达

题解

代码实现

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>using namespace std;const int MAX = 100005;const int NIL = -1;struct Node {int parent, left, right;};Node Tree[MAX];int n, Depth[MAX], Height[MAX];int getDegree(int u) {int deg = 0;if (Tree[u].left != NIL)deg++;if (Tree[u].right != NIL)deg++;return deg;}void setDepth(int u, int depth) {if (u == NIL)return;Depth[u] = depth;setDepth(Tree[u].left, depth + 1);setDepth(Tree[u].right, depth + 1);}int setHeight(int u) {int h1 = 0, h2 = 0;if (Tree[u].left != NIL)h1 = setHeight(Tree[u].left) + 1;if (Tree[u].right != NIL)h2 = setHeight(Tree[u].right) + 1;return Height[u] = max(h1, h2);}int getSibling(int u) {if (Tree[u].parent == NIL)return NIL;//存在左兄弟if (Tree[Tree[u].parent].left != u && Tree[Tree[u].parent].left != NIL)return Tree[Tree[u].parent].left;//存在右兄弟if (Tree[Tree[u].parent].right != u && Tree[Tree[u].parent].right != NIL)return Tree[Tree[u].parent].right;return NIL;}void print(int u) {printf("node %d: parent = %d, sibling = %d, degree = %d, depth = %d, height = %d, ", u, Tree[u].parent, getSibling(u), getDegree(u), Depth[u], Height[u]);if (Tree[u].parent == NIL)printf("root\n");else if (Tree[u].left != NIL || Tree[u].right != NIL)printf("internal node\n");elseprintf("leaf\n");}int main() {int n;int u, l, r, root;scanf("%d", &n);for (int i = 0; i < n; i++) {Tree[i].parent = Tree[i].left = Tree[i].right = NIL;}for (int i = 0; i < n; i++) {scanf("%d %d %d", &u, &l, &r);Tree[u].left = l;Tree[u].right = r;Tree[l].parent = u;Tree[r].parent = u;}for (int i = 0; i < n; i++) {if (Tree[i].parent == NIL)root = i;}setHeight(root);setDepth(root, 0);for (int i = 0; i < n; i++)print(i);return 0;}

8.4 树的遍历

题解

前序遍历:F, B, A, D, C, E, G, I, H

中序遍历:A, B, C, D, E, F, G, H, I

后续遍历:A, C, E, D, B, H, I, G, F

层序遍历:F, B, G, A, D, I, C, E, H

代码实现

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>using namespace std;const int MAX = 100005;const int NIL = -1;struct Node {int parent, left, right;};Node Tree[MAX];int n;//前序排序void PreorderTreeWalk(int u) {if (u == NIL)return;printf(" %d", u);PreorderTreeWalk(Tree[u].left);PreorderTreeWalk(Tree[u].right);}//中序排序void InorderTreeWalk(int u) {if (u == NIL)return;InorderTreeWalk(Tree[u].left);printf(" %d", u);InorderTreeWalk(Tree[u].right);}//后序排序void PostorderTreeWalk(int u) {if (u == NIL)return;PostorderTreeWalk(Tree[u].left);PostorderTreeWalk(Tree[u].right);printf(" %d", u);}int main() {int n;int u, l, r, root;scanf("%d", &n);for (int i = 0; i < n; i++) {Tree[i].parent = Tree[i].left = Tree[i].right = NIL;}for (int i = 0; i < n; i++) {scanf("%d %d %d", &u, &l, &r);Tree[u].left = l;Tree[u].right = r;Tree[l].parent = u;Tree[r].parent = u;}for (int i = 0; i < n; i++) {if (Tree[i].parent == NIL)root = i;}printf("Preorder\n");PreorderTreeWalk(root);printf("\nInorder\n");InorderTreeWalk(root);printf("\nPostorder\n");PostorderTreeWalk(root);printf("\n");return 0;}

8.5 树遍历的应用 —— 树的重建

题解

图中后序遍历的结果为:3 5 6 4 2 8 9 7 1

代码实现

1、已知前序遍历和中序遍历,求后续遍历。

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<vector>using namespace std;vector<int> pre, in, post;int pos;int n, k;void reconstruction(int left, int right) {// 遍历到叶结点if (left >= right)return;// 当前子树的根int root = pre[pos++];// 找出当前根的值在中序数组里的下标int m = distance(in.begin(), find(in.begin(), in.end(), root));reconstruction(left, m);reconstruction(m + 1, right);//存入到后序数组post.push_back(root);}void solve() {pos = 0;reconstruction(0, pre.size());for (int i = 0; i < n; i++) {printf("%d%c", post[i], i == n-1?'\n':' ');}}int main() {scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%d", &k);pre.push_back(k);}for (int i = 0; i < n; i++) {scanf("%d", &k);in.push_back(k);}solve();return 0;}

2、已知后续遍历和中序遍历求前序遍历

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<vector>using namespace std;vector<int> pre, in, post;int pos;int n, k;void reconstruction(int left, int right) {// 遍历到叶结点if (left >= right)return;// 当前子树的根int root = pre[pos--];// 找出当前根的值在中序数组里的下标int m = distance(in.begin(), find(in.begin(), in.end(), root));reconstruction(m + 1, right); // 注意优先建立左边的树,根节点时从后往前的reconstruction(left, m);//存入到后序数组post.push_back(root);}void solve() {pos = n - 1;reconstruction(0, pre.size());for (int i = n - 1; i >= 0; i--) {printf("%d%c", post[i], i == n-1?'\n':' ');}}int main() {scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%d", &k);pre.push_back(k);}for (int i = 0; i < n; i++) {scanf("%d", &k);in.push_back(k);}solve();return 0;}

3、已知前序遍历和后序遍历不可求中序遍历

4、已知前序||中序||后序遍历(仅该树为完全二叉树),求层序遍历

#include<bits/stdc++.h>using namespace std;int n,a[100],tree[100];int idx=1;void f(int x){if(x > n) return ;tree[x] = a[idx++]; //已知前序遍历,求层序遍历f(x << 1);//tree[x] = a[idx++]; //已知中序遍历,求层序遍历f((x << 1) + 1);//tree[x] = a[idx++];//已知后序遍历,求层序遍历}int main(){scanf("%d",&n);for(int i = 1; i <= n; i++)scanf("%d",&a[i]);f(1);printf("层次遍历:");for(int i = 1; i <= n; i++)printf("%d ",tree[i]);return 0;}

5、已知层序遍历,求前中后遍历(仅满足树为完全二叉树时)

#include<stdio.h>const int N=100;int pre[N],in[N],post[N],tree[N],idx;;int n;void f(int x){pre[idx++]=tree[x]; //求前序遍历if(x<<1<=n)f(x<<1);//in[idx++]=tree[x]; //求中序遍历if((x<<1)+1<=n) //记得加括号,不然会先加1后乘2f((x<<1)+1);//post[idx++]=tree[x]; //求后序遍历}int main(){scanf("%d",&n);for(int i=1;i<=n;i++) //输入层遍历scanf("%d",&tree[i]);f(1);for(int i=0;i<n;i++) //输出printf("%d ",pre[i]);return 0;}

第九章 二叉搜索树

9.2 二叉搜索树——插入

题解

代码实现

#include<iostream>#include<cstdio>using namespace std;const int MAX = 100005;struct Node {int key;Node *parent, *left, *right;};Node *root, *NIL;//前序排序void PreorderTreeWalk(Node *u) {if (u == NIL)return;printf(" %d", u->key);PreorderTreeWalk(u->left);PreorderTreeWalk(u->right);}//中序排序void InorderTreeWalk(Node *u) {if (u == NIL)return;InorderTreeWalk(u->left);printf(" %d", u->key);InorderTreeWalk(u->right);}void insert(int value) {Node *y = NIL, *x = root;// 初始化 z 节点作为要插入的节点Node *z = new Node(); // Node *z = (Node *)malloc(sizeof(Node))z->key = value;z->left = z->right = NIL;// 从根结点往下遍历while (x != NIL) {y = x; // 记录搜索下去的前一个节点,作为 待插入节点 z 的父节点// z 比 x 小, 则从x的左侧遍历// z 比 x 大, 则从x的右侧遍历if (z->key < x->key)x = x->left;elsex = x->right;}z->parent = y;// 没有父结点的是rootif (y == NIL) {root = z;}else {// z 比 y 小, 则在y的左侧// z 比 y 大, 则在y的右侧if (z->key < y->key)y->left = z;elsey->right = z;}}int main() {int n, value;char s[200];scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%s", s);if (s[0] == 'i') {scanf("%d", &value);insert(value);}else {InorderTreeWalk(root);printf("\n");PreorderTreeWalk(root);printf("\n");}}return 0;}

9.3 二叉搜索树——搜索

题解

代码实现

#include<iostream>#include<cstdio>using namespace std;const int MAX = 100005;struct Node {int key;Node *parent, *left, *right;};Node *root, *NIL;//前序排序void PreorderTreeWalk(Node *u) {if (u == NIL)return;printf(" %d", u->key);PreorderTreeWalk(u->left);PreorderTreeWalk(u->right);}//中序排序void InorderTreeWalk(Node *u) {if (u == NIL)return;InorderTreeWalk(u->left);printf(" %d", u->key);InorderTreeWalk(u->right);}void insert(int value) {Node *y = NIL, *x = root;Node *z = new Node();z->key = value;z->left = z->right = NIL;// 从根结点往下遍历while (x != NIL) {y = x;// z 比 x 小, 则从x的左侧遍历// z 比 x 大, 则从x的右侧遍历if (z->key < x->key)x = x->left;elsex = x->right;}z->parent = y;// 没有父结点的是rootif (y == NIL) {root = z;}else {// z 比 y 小, 则在y的左侧// z 比 y 大, 则在y的右侧if (z->key < y->key)y->left = z;elsey->right = z;}}Node * find(Node *u, int value) {// 从根结点开始遍历下去while (u != NIL && u->key != value) {if (value < u->key)u = u->left;elseu = u->right;}return u;}int main() {int n, value;Node * f;char s[200];scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%s", s);if (s[0] == 'i') {scanf("%d", &value);insert(value);}else if (s[0] == 'f') {scanf("%d", &value);f = find(root,value);if (f != NIL)printf("yes\n");elseprintf("no\n");}else {InorderTreeWalk(root);printf("\n");PreorderTreeWalk(root);printf("\n");}}return 0;}

9.4 二叉搜索树——删除

题解

代码实现

#include<iostream>#include<cstdio>using namespace std;const int MAX = 100005;struct Node {int key;Node *parent, *left, *right;};Node *root, *NIL;//前序排序void PreorderTreeWalk(Node *u) {if (u == NIL)return;printf(" %d", u->key);PreorderTreeWalk(u->left);PreorderTreeWalk(u->right);}//中序排序void InorderTreeWalk(Node *u) {if (u == NIL)return;InorderTreeWalk(u->left);printf(" %d", u->key);InorderTreeWalk(u->right);}void insert(int value) {Node *y = NIL, *x = root;Node *z = new Node();z->key = value;z->left = z->right = NIL;// 从根结点往下遍历while (x != NIL) {y = x;// z 比 x 小, 则从x的左侧遍历// z 比 x 大, 则从x的右侧遍历if (z->key < x->key)x = x->left;elsex = x->right;}z->parent = y;// 没有父结点的是rootif (y == NIL) {root = z;}else {// z 比 y 小, 则在y的左侧// z 比 y 大, 则在y的右侧if (z->key < y->key)y->left = z;elsey->right = z;}}// 首先找到待删除值对应的节点,返回节点Node * find(Node *u, int value) {// 从根结点开始遍历下去while (u != NIL && u->key != value) {if (value < u->key)u = u->left;elseu = u->right;}return u;}// 树的最小值Node *treeMinimum(Node * x) {while (x->left != NIL)x = x->left;return x;}// case 3 ,搜索后一个结点Node *treeSuccessor(Node *x) {if (x->right != NIL)return treeMinimum(x->right);Node *y = x->parent;while (y != NIL && x == y->right) {x = y;x = y->parent;}return y;}// 传入的节点 z 即需要删除的节点void treeDelete(Node * z) {Node *y, *x; // 要删除的对象和 y 的子结点// 确定要删除的结点if (z->left == NIL || z->right == NIL)y = z;elsey = treeSuccessor(z);// 确定 y 的子结点xif (y->left != NIL)x = y->left;elsex = y->right;// 让子结点链接父结点if (x != NIL)x->parent = y->parent;// 让父结点链接子结点if (y->parent == NIL)root = x;else {if (y == y->parent->left)y->parent->left = x;elsey->parent->right = x;}// case 3if (y != z)z->key = y->key;delete y;}int main() {int n, value;Node * f;char s[200];scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%s", s);if (s[0] == 'i') {scanf("%d", &value);insert(value);}else if (s[0] == 'f') {scanf("%d", &value);f = find(root, value);if (f != NIL)printf("yes\n");elseprintf("no\n");}else if (s[0] == 'd') {scanf("%d", &value);treeDelete(find(root, value));}else {InorderTreeWalk(root);printf("\n");PreorderTreeWalk(root);printf("\n");}}return 0;}

第十章 堆

10.2 完全二叉树

题解

代码实现

#include <iostream>#include <cstdio>using namespace std;// 分别求出结点i的父结点,左子结点、右子结点int parent(int i) {return i / 2; }int left(int i) {return 2 * i; }int right(int i) {return 2 * i + 1; }int main(){int H[300];int n;scanf("%d", &n);for (int i = 1; i <= n; i++)scanf("%d", &H[i]);for (int i = 1; i <= n; i++) {printf("node %d: key = %d, ", i, H[i]);if (parent(i) >= 1)printf("parent key = %d, ", H[parent(i)]);if (left(i) <= n) printf("left key = %d, ", H[left(i)]);if (right(i) <= n)printf("right key = %d, ", H[right(i)]);printf("\n");}return 0;}

10.3 最大/最小堆

题解

代码实现

#include <iostream>#include <cstdio>#include <algorithm>using namespace std;const int maxx = 2000000;int A[maxx + 1];int n;void maxHeapify(int i) {int left = 2 * i, right = 2 * i + 1;int largest;// 从左子结点、自身、右子结点选出值最大的结点,然后继续往下递归if (left <= n && A[left] > A[i])largest = left;elselargest = i;if (right <= n && A[right] > A[largest])largest = right;if (largest != i) {swap(A[i], A[largest]);maxHeapify(largest);}}int main(){scanf("%d", &n);for (int i = 1; i <= n; i++)scanf("%d", &A[i]);for (int i = n / 2; i >= 1; i--)maxHeapify(i);for (int i = 1; i <= n; i++)printf(" %d", A[i]);printf("\n");return 0;}

10.4 优先级队列

题解

代码实现

#include <iostream>#include <cstdio>#include <algorithm>using namespace std;const int maxx = 2000000;const int INF = 1 << 30;int A[maxx + 1];int n;void maxHeapify(int i) {int left = 2 * i, right = 2 * i + 1;int largest;// 从左子结点、自身、右子结点选出值最大的结点,然后继续往下递归if (left <= n && A[left] > A[i])largest = left;elselargest = i;if (right <= n && A[right] > A[largest])largest = right;if (largest != i) {swap(A[i], A[largest]);maxHeapify(largest);}}int extract() {int maxv;if (n < 1)return -INF;maxv = A[1];A[1] = A[n--];maxHeapify(1);return maxv;}int insert(int key) {n++;int i = n;A[n] = -INF;if (key < A[i])return -INF;A[i] = key;while (i > 1 && A[i / 2] < A[i]) {swap(A[i], A[i / 2]);i /= 2;}}int main(){char op[20];int k;while (scanf("%s", op) != EOF&&op[2] != 'd') {if (op[0] == 'i') {scanf("%d", &k);insert(k);}else {printf("%d\n", extract());}}return 0;}

10.5 通过标准库实现优先级队列

第十一章 动态规划

11.1 动态规划法的概念

11.2 斐波那契数列

题解

代码实现

#include <iostream>#include <cstdio>using namespace std;int main(){int F[45],n;F[0] = F[1] = 1;for (int i = 2; i <= 44; i++)F[i] = F[i - 1] + F[i - 2];scanf("%d", &n);printf("%d\n", F[n]);return 0;

11.3 最长公共子序列

题解

代码实现

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxx = 1010;int c[maxx][maxx];int lcs(char s1[],char s2[]) {int m = strlen(s1), n = strlen(s2);for (int i = 1; i <= m; i++)c[i][0] = 0;for (int i = 1; i <= n; i++)c[0][i] = 0;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (s1[i] == s2[j])c[i+1][j+1] = c[i][j] + 1;elsec[i+1][j+1] = max(c[i][j+1], c[i + 1][j]);}}return c[m][n];}int main(){char s1[maxx], s2[maxx];int t;scanf("%d", &t);for (int i = 0; i < t; i++) {scanf("%s %s", s1, s2);printf("%d\n",lcs(s1,s2));}return 0;

11.4 矩阵链乘法

题解

代码实现

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxx = 110;const int INF = 1 << 30;int main(){int n, p[maxx], m[maxx][maxx];scanf("%d", &n);for (int i = 1; i <= n; i++)scanf("%d %d", &p[i - 1], &p[i]);for (int i = 1; i <= n; i++)m[i][i] = 0;for (int l = 2; l <= n; l++) {for (int i = 1; i <= n - l + 1; i++) {int j = i + l - 1;m[i][j] = INF;for (int k = i; k <= j - 1; k++)m[i][j] = min(m[i][j], m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j]);}}printf("%d\n", m[1][n]);return 0;}

第十二章 图

12.1 挑战问题之前——图

12.2 图的表示

题解

代码实现

#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int maxx = 110;int main(){int n, m[maxx][maxx]; // 邻接矩阵int u, num, v;scanf("%d", &n);memset(m, 0, sizeof(m));for (int i = 1; i <= n; i++) {scanf("%d %d", &u, &num);for (int j = 1; j <= num; j++) {scanf("%d", &v);m[u][v] = 1; // u 与 v 之间画一条边}}for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)printf("%d%c", m[i][j], j == n ? '\n' : ' ');return 0;}

12.3 深度优先搜索

题解

代码实现

#include <iostream>#include <cstdio>#include <cstring>#include <stack>using namespace std;const int maxx = 110;int n, m[maxx][maxx];int u, num, v;int d[maxx], f[maxx];int flag[maxx];int nowtime = 1;void dfs(int u) {// 入栈时间flag[u] = 1;d[u] = nowtime++;for (int i = 1; i <= n; i++) {if (flag[i] == 0 && m[u][i] == 1) {dfs(i);}}//出栈时间f[u] = nowtime++;}int main(){scanf("%d", &n);memset(m, 0, sizeof(m));memset(f, 0, sizeof(f));for (int i = 1; i <= n; i++) {scanf("%d %d", &u, &num);for (int j = 1; j <= num; j++) {scanf("%d", &v);m[u][v] = 1;}}for (int i = 1; i <= n; i++) {if(flag[i] == 0)dfs(i);}for (int i = 1; i <= n; i++) {printf("%d %d %d\n", i, d[i], f[i]);}return 0;}

12.4 广度优先搜索

题解

代码实现

#include <iostream>#include <cstdio>#include <cstring>#include <queue>using namespace std;const int maxx = 110;int n, m[maxx][maxx];int u, num, v;int flag[maxx];int d[maxx];void bfs() {queue<int>q;q.push(1);d[1] = 0;while (!q.empty()) {int u = q.front();q.pop();for (int i = 2; i <= n; i++) {if (m[u][i] == 1 && flag[i] == 0) {// 标记为已经访问flag[i] = 1;// 更新长度d[i] = d[u] + 1;// 压入栈内q.push(i);}}}}int main(){scanf("%d", &n);memset(m, 0, sizeof(m));for (int i = 1; i <= n; i++) {scanf("%d %d", &u, &num);// 初始化flag[i] = 0;d[i] = -1;for (int j = 1; j <= num; j++) {scanf("%d", &v);m[u][v] = 1;}}bfs();for (int i = 1; i <= n; i++) {printf("%d %d\n", i, d[i]);}return 0;}

12.5 连 通 分 量

题解

代码实现

#include <iostream>#include <cstdio>#include <cstring>#include <stack>#include <vector>using namespace std;const int maxx = 100010;int n, m;int u, num, v;int flag[maxx];int color[maxx];vector<int> G[maxx];int c = 1;void dfs(int t) {stack<int>s;s.push(t);color[t] = c;while (!s.empty()) {int u = s.top(); s.pop();int len = G[u].size();for (int i = 0; i < len; i++) {int v = G[u][i];if (flag[v] == 0) {color[v] = c;flag[v] = 1;s.push(v);}}}}int main(){int q;memset(flag, 0, sizeof(flag));scanf("%d %d", &n, &m);for (int i = 0; i < m; i++) {scanf("%d %d", &u, &v);//将顶点v添加到G[u]数组中G[u].push_back(v);G[v].push_back(u);}for (int i = 0; i < n; i++) {if (flag[i] == 0) {dfs(i);c++;}}scanf("%d", &q);for (int i = 0; i < q; i++) {scanf("%d %d", &u, &v);if (color[u] == color[v]) {printf("yes\n");}else {printf("no\n");}}return 0;}

第十三章 加权图

13.1 挑战问题之前——加权图

最小生成树

最短路径

13.2 最小生成树

题解

代码实现

#include <iostream>#include <cstdio>#include <cstring>#include <stack>#include <vector>using namespace std;const int maxx = 1010;const int INF = 1 << 30;int n, m[maxx][maxx];int u, num, v;int flag[maxx];int prim() {// d数组是保存V-T, p数组是记录MST的int d[maxx], p[maxx];for (int i = 0; i < n; i++) {d[i] = INF;p[i] = -1;flag[i] = 0;}d[0] = 0;while (1) {int minv = INF;u = -1;// 比较出权值最小的边for (int i = 0; i < n; i++) {if (minv > d[i] && flag[i] == 0) {u = i;minv = d[i];}}if (u == -1)break;// 标记已经加入MSTflag[u] = 1;// 更新未访问的点与已经访问的点之间的最小的边(相对于每个点)for (int v = 0; v < n; v++) {if (flag[v] == 0 && m[u][v] != INF && d[v] > m[u][v]) {d[v] = m[u][v];p[v] = u;}}}int ans = 0;for (int i = 0; i < n; i++)if (p[i] != -1)ans += m[i][p[i]];return ans;}int main(){memset(flag, 0, sizeof(flag));scanf("%d", &n);for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {scanf("%d", &m[i][j]);if (m[i][j] == -1)m[i][j] = INF;}}printf("%d\n", prim());return 0;}

13.3 单源最短路径

题解

代码实现

#include <iostream>#include <cstdio>#include <cstring>#include <stack>#include <vector>using namespace std;const int maxx = 1010;const int INF = 1 << 30;int n, m[maxx][maxx];int u, v ,k, c;int flag[maxx];void dijkstra() {int d[maxx];for (int i = 0; i < n; i++) {d[i] = INF;flag[i] = 0;}d[0] = 0;while (1) {int minv = INF;u = -1;// 比较出权值最小的边for (int i = 0; i < n; i++) {if (minv > d[i] && flag[i] == 0) {u = i;minv = d[i];}}if (u == -1)break;// 标记已经加入Sflag[u] = 1;// 更新经由u结点,V-S的v结点的最小成本for (int v = 0; v < n; v++) {if (flag[v] == 0 && m[u][v] != INF && d[v] > d[u] + m[u][v]) {d[v] = d[u] + m[u][v];}}}for (int i = 0; i < n; i++)printf("%d %d\n", i, d[i] == INF ? -1 : d[i]);}int main(){scanf("%d", &n);for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {m[i][j] = INF;}}for (int i = 0; i < n; i++) {scanf("%d %d", &u, &k);for (int j = 0; j < k; j++) {scanf("%d %d", &v, &c);m[u][v] = c;}}dijkstra();return 0;}

堆优化的单源最短路径

#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <vector>#include <algorithm>using namespace std;const int maxx = 10010;const int INF = 1 << 30;int n;int flag[maxx];// 加权有向图的邻接表表示法,pair.first是顶点v,pair.second是权值vector<pair<int, int> > adj[maxx];void dijkstra() {priority_queue<pair<int, int> > PQ;int d[maxx];for (int i = 0; i < n; i++) {d[i] = INF;flag[i] = 0;}d[0] = 0;PQ.push(make_pair(0, 0));while (!PQ.empty()) {pair<int, int> f = PQ.top(); PQ.pop();int u = f.second;// 标记已经加入Sflag[u] = 1;//如果不是最小最短路径则忽略if (d[u] < f.first *(-1))continue;int len = adj[u].size();for (int j = 0; j < len; j++) {int v = adj[u][j].first;if (flag[v] == 0 && d[v] > d[u] + adj[u][j].second) {d[v] = d[u] + adj[u][j].second;// priority_queue默认取最大值,所以乘以-1PQ.push(make_pair(d[v] * (-1), v));}}}for (int i = 0; i < n; i++)printf("%d %d\n", i, d[i] == INF ? -1 : d[i]);}int main(){int u, v, k, c;scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%d %d", &u, &k);for (int j = 0; j < k; j++) {scanf("%d %d", &v, &c);adj[u].push_back(make_pair(v, c));}}dijkstra();return 0;}

第十四章 高等数据结构

14.1 互质的集合

题解

代码实现

#include <iostream>#include <cstdio>#include <vector>using namespace std;class DisjointSet {public :// rank记录树的高度vector<int> rank, p;DisjointSet() {};DisjointSet(int size) {rank.resize(size, 0);p.resize(size, 0);for (int i = 0; i < size; i++)makeSet(i);}void makeSet(int i) {p[i] = i;rank[i] = 0;}bool same(int x, int y) {return findSet(x) == findSet(y);}void unite(int x, int y) {link(findSet(x), findSet(y));}void link(int x, int y) {// 包含x的树的高度更高,则将y的树合并到x上if (rank[x] > rank[y])p[y] = x;else {p[x] = y;if (rank[x] == rank[y])rank[y]++;}}int findSet(int x) {if (x != p[x])p[x] = findSet(p[x]);return p[x];}};int main(){int n, a, b,t, q;scanf("%d %d", &n, &q);DisjointSet ds = DisjointSet(n);for (int i = 0; i < q; i++) {scanf("%d %d %d", &t, &a, &b);if (t == 0)ds.unite(a, b);elseprintf("%d\n", ds.same(a, b) ? 1 : 0);}return 0;}

第十五章 高等图算法

15.1 所有点对间最短路径

题解

代码实现

#include <iostream>#include <cstdio>#include <vector>#include <algorithm>using namespace std;typedef long long LL;const int maxx = 110;const LL INF = (1LL << 32);int n,q;LL d[maxx][maxx];void floyd() {for (int k = 0; k < n; k++) {for (int i = 0; i < n; i++) {if (d[i][k] == INF)continue;for (int j = 0; j < n; j++) {if (d[k][j] == INF)continue;d[i][j] = min(d[i][j], d[i][k] + d[k][j]);}}}}int main(){int u, v, c;scanf("%d %d", &n, &q);for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++)d[i][j] = i == j ? 0 : INF;}// 输入权值for (int i = 0; i < q; i++) {scanf("%d %d %d", &u, &v, &c);d[u][v] = c;}floyd();// 判断是否存在负环bool negative = false;for (int i = 0; i < n; i++)if (d[i][i] < 0)negative = true;if (negative)printf("NEGATIVE CYCLE\n");else {for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {if (d[i][j] == INF)printf("INF");elseprintf("%d", d[i][j]);printf("%c", j == n - 1 ? '\n' : ' ');}}}return 0;}

15.2 拓 扑 排 序

题解

代码实现

#include <iostream>#include <cstdio>#include <vector>#include <queue>#include <list>#include <algorithm>using namespace std;const int maxx = 100010;const int INF = 1 << 30;vector<int>G[maxx];list<int>out;bool flag[maxx];int n;int indeg[maxx];void bfs(int s) {queue<int> q;q.push(s);while (!q.empty()) {int u = q.front(); q.pop();out.push_back(u);for (int i = 0; i < G[u].size(); i++) {int v = G[u][i];indeg[v]--;if (indeg[v] == 0 && flag[v] == 0) {flag[v] = true;q.push(v);}}}}void tsort() {for (int i = 0; i < n; i++) {indeg[i] = 0;flag[i] = false;}for (int u = 0; u < n; u++) {for (int i = 0; i < G[u].size(); i++) {int v = G[u][i];indeg[v]++;}}for (int u = 0; u < n; u++) {if (indeg[u] == 0 && flag[u] == 0)bfs(u);}for (list<int>::iterator it = out.begin(); it != out.end(); it++)printf("%d\n", *it);}int main(){int s, t, m;scanf("%d %d", &n, &m);for (int i = 0; i < m; i++) {scanf("%d %d", &s, &t);G[s].push_back(t);}tsort();return 0;}

15.4 树 的 直 径

题解

代码实现

#include <iostream>#include <cstdio>#include <vector>#include <queue>using namespace std;const int maxx = 100010;const int INF = 1 << 30;class Edge {public:int t, w;Edge() {};Edge(int t ,int w):t(t), w(w) {};};vector<Edge> G[maxx];int n, d[maxx];bool vis[maxx];int cnt;void bfs(int s) {for (int i = 0; i < n; i++)d[i] = INF;queue<int> Q;Q.push(s);d[s] = 0;while (!Q.empty()) {int u = Q.front(); Q.pop();int len = G[u].size();for (int i = 0; i < len; i++) {Edge e = G[u][i];if (d[e.t] == INF) {d[e.t] = d[u] + e.w;Q.push(e.t);}}}}void solve() {// 从任选的结点s出发,选择距离s最远的结点tgtbfs(0);int maxv = 0, tgt = 0;for (int i = 0; i < n; i++) {if (d[i] == INF)continue;if (maxv < d[i]) {maxv = d[i];tgt = i;}}//从tgt出发,求结点tgt到最远结点的距离maxvbfs(tgt);maxv = 0;for (int i = 0; i < n; i++) {if (d[i] == INF)continue;maxv = max(maxv, d[i]);}printf("%d\n", maxv);}int main() {int s, t, w;scanf("%d", &n);for (int i = 0; i < n - 1; i++) {scanf("%d %d %d", &s, &t, &w);// 无向图G[s].push_back(Edge(t, w));G[t].push_back(Edge(s, w));}solve();return 0;}

15.5 最小生成树

题解

代码实现

第十七章 动态规划 略

第十八章 数论

算法之经典数学知识

第十九章 启发式搜索 略

19.1 八皇后问题

19.2 九宫格拼图

如果觉得《【操作指导 | 代码实现】挑战程序设计竞赛2:算法和数据结构》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。