MOOC数据结构 OJ题记录

  • PA1-1 范围查询 (对应课程:绪论+向量)
  • PA1-2 祖玛问题 (对应课程:列表)
  • PA 1-3 灯塔(归并)
  • PA 2-1 列车调度(栈)
  • PA 2-2 真二叉树重构
  • PA2-3 旅行商(TSP)

很多代码都是参考这位博主的( 18Temp),真的是很简洁到… 后面第二大部分的题目得分析1小时才完全看懂自己能写的…

PA1-1 范围查询 (对应课程:绪论+向量)

描述
数轴上有n个点,对于任一闭区间 [a, b],试计算落在其内的点数。
输入
第一行包括两个整数:点的总数n,查询的次数m。
第二行包含n个数,为各个点的坐标。
以下m行,各包含两个整数:查询区间的左、右边界a和b。
输出
对每次查询,输出落在闭区间[a, b]内点的个数。

首先… 一开始没看OJ不能用库 /笑哭,虽然我没看课 看完C++就直接跳到编程去做了,然后乖乖看课(虽然以前看过一次程序设计基础 但是没有结合代码的,就是大概了解了有些啥方法
整体,贴代码:(PS:我认为如何想在效率进行改进:

  1. qsort() 是C语言的标准库,使用的是快速排序法,类似于冒泡但是是lo hi的对换,感兴趣可以百度一下,能看源码。 -> 所以引发了这里可以不用库,n大于一定数值采用归并排序(上课讲到过)
  2. 主要是排序与查找算法都采用最优应该就可以(查找xx

以下为博主的代码(看了看课,看着伪代码 差不多写了)

//#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#define L 500000
int arr[L];
//qsort需要一个比较两个元素的函数
int cmpfunc(const void *a, const void *b)
{return *(int*)a - *(int*)b;
}
//此处使用二分查找法 C版本
int binsearch(int *a, int lo, int hi,int e)
{while (lo<hi){int mi = (lo + hi) >> 1;// 左移的除2效率更高(e < a[mi]) ? hi = mi : lo = mi + 1;}return --lo;
}
int main()
{int n, m;int a, b;scanf("%d %d", &n, &m);//比cin的效率高for (int i = 0; i < n; i++){scanf("%d", arr + i);}qsort(arr, n, sizeof(int), cmpfunc);//查询了一下C语言库中的qsort快速排序法,目前最好的内部排序(但是看复杂度似乎没有归并的效率高)for (int i = 0; i < m; i++){scanf("%d %d", &a, &b);int nleft = binsearch(arr, 0, n, a);int nright = binsearch(arr, 0, n, b);if (arr[nleft]==a & nleft>=0)//数组中有闭合区间的 左侧值,需要在整体多加1{nleft--;}printf("%d\n", nright - nleft);//比cout效率高}return 0;
}

PA1-2 祖玛问题 (对应课程:列表)

描述
祖玛是一款曾经风靡全球的游戏,其玩法是:在一条轨道上初始排列着若干个彩色珠子,其中任意三个相邻的珠子不会完全同色。此后,你可以发射珠子到轨道上并加入原有序列中。一旦有三个或更多同色的珠子变成相邻,它们就会立即消失。这类消除现象可能会连锁式发生,其间你将暂时不能发射珠子。开发商最近准备为玩家写一个游戏过程的回放工具。他们已经在游戏内完成了过程记录的功能,而回放功能的实现则委托你来完成。游戏过程的记录中,首先是轨道上初始的珠子序列,然后是玩家接下来所做的一系列操作。你的任务是,在各次操作之后及时计算出新的珠子序列。
输入
第一行是一个由大写字母’A’~'Z’组成的字符串,表示轨道上初始的珠子序列,不同的字母表示不同的颜色。第二行是一个数字n,表示整个回放过程共有n次操作。接下来的n行依次对应于各次操作。每次操作由一个数字k和一个大写字母Σ描述,以空格分隔。其中,Σ为新珠子的颜色。若插入前共有m颗珠子,则k ∈ [0, m]表示新珠子嵌入之后(尚未发生消除之前)在轨道上的位序。
输出
输出共n行,依次给出各次操作(及可能随即发生的消除现象)之后轨道上的珠子序列。如果轨道上已没有珠子,则以“-”表示。

此处是一位大神拿向量做的:大家感兴趣可以看一看 Tsinghua MOOC 祖玛(Zuma)

//#include "stdafx.h"
#include <iostream>
#include <cstring>
#include <cstdio>#define L 20000
char ch[L];
int chsize = 0;
char temp[L];
int pos;
bool judg(int tpos)
{int head = tpos, last = tpos;char elem = ch[tpos];while (ch[head]==elem && head){head--;}if (ch[head]!=elem){head++;}while (ch[last]==elem){last++;if (last==chsize){break;}}    if (last-head>2){strcpy(temp, ch + last);strcpy(ch + head, temp);chsize = chsize + head - last;pos = head;return 1;}else{return 0;}}int main()
{char tch;gets(ch);while (ch[chsize] >= 'A' && ch[chsize] <= 'Z'){chsize++;}    int n;scanf("%d", &n);while (n--){scanf("%d %c", &pos,&tch);        strcpy(temp, ch + pos);strcpy(ch + pos + 1, temp);ch[pos] = tch;chsize++;while (chsize&&judg(pos));if (chsize>0){puts(ch);}else{puts("-");}}    return 0;
}

PA 1-3 灯塔(归并)

描述
海上有许多灯塔,为过路船只照明。
图一)如图一所示,每个灯塔都配有一盏探照灯,照亮其东北、西南两个对顶的直角区域。探照灯的功率之大,足以覆盖任何距离。灯塔本身是如此之小,可以假定它们不会彼此遮挡。
(图二)若灯塔A、B均在对方的照亮范围内,则称它们能够照亮彼此。比如在图二的实例中,蓝、红灯塔可照亮彼此,蓝、绿灯塔则不是,红、绿灯塔也不是。现在,对于任何一组给定的灯塔,请计算出其中有多少对灯塔能够照亮彼此。
输入
共n+1行。第1行为1个整数n,表示灯塔的总数。第2到n+1行每行包含2个整数x, y,分别表示各灯塔的横、纵坐标。
输出
1个整数,表示可照亮彼此的灯塔对的数量。
实际题目

//#include "stdafx.h"#include <cstdio>
using namespace std;
#define ll long long
#define L 4000000
struct Point {ll x, y;
}points[L];
Point *bs = new Point[L];
ll *b = new ll[L];
ll y[L], countsum = 0;
void MergeS(Point *elem, int sta, int mid, int end)
{Point *lo = elem + sta, *mi = elem + mid;int left = mid - sta, right = end - mid;for (int i = 0; i < left; bs[i] = lo[i++]);for (int i = 0, j = 0, k = 0; j < left;){if ((right<=k)|| (bs[j].x<mi[k].x)){lo[i++] = bs[j++];}if ((k < right) && (mi[k].x < bs[j].x)){lo[i++] = mi[k++];}}
}
void Mergell(ll *elem, int sta, int mid, int end)
{ll *a = elem + sta, *c = elem + mid;int left = mid - sta, right = end - mid;for (int i = 0; i < left; b[i] = a[i++]);for (int i = 0, j = 0, k = 0; j < left;){if ((right <= k )|| (b[j]<c[k])){a[i++] = b[j++];if (k<right){countsum += right - k;}}if ((k < right) && (c[k] < b[j])){a[i++] = c[k++];}}
}
void MergeSort(Point *elem, int sta, int end)
{if (end-sta<2){return;}int mid = (sta + end) >> 1;;MergeSort(elem,sta, mid);MergeSort(elem,mid, end);MergeS(elem,sta, mid, end);
}
void MergeSortY(ll *elem, int sta, int end)
{if (end - sta<2){return;}int mid = (sta + end) >> 1;MergeSortY(elem,sta, mid);MergeSortY(elem,mid, end);Mergell(elem,sta, mid, end);
}
int main()
{int n;scanf("%d", &n);for (int i = 0; i < n; i++){scanf("%lld %lld", &points[i].x, &points[i].y);}MergeSort(points, 0, n);for (int i = 0; i < n; i++){y[i] = points[i].y;}MergeSortY(y, 0, n);printf("%lld\n", countsum);return 0;
}

PA 2-1 列车调度(栈)

描述
某列车调度站的铁道联接结构如Figure 1所示。其中,A为入口,B为出口,S为中转盲端。所有铁道均为单轨单向式:列车行驶的方向只能是从A到S,再从S到B;另外,不允许超车。因为车厢可在S中驻留,所以它们从B端驶出的次序,可能与从A端驶入的次序不同。不过S的容量有限,同时驻留的车厢不得超过m节。设某列车由编号依次为{1, 2, …, n}的n节车厢组成。调度员希望知道,按照以上交通规则,这些车厢能否以{a1, a2, …, an}的次序,重新排列后从B端驶出。如果可行,应该以怎样的次序操作?
输入
共两行。第一行为两个整数n,m。第二行为以空格分隔的n个整数,保证为{1, 2, …, n}的一个排列,表示待判断可行性的驶出序列{a1,a2,…,an}。
输出
若驶出序列可行,则输出操作序列,其中push表示车厢从A进入S,pop表示车厢从S进入B,每个操作占一行。若不可行,则输出No。
实际题目

这一篇是我写的时候参考的,一目了然,非常好的一个解法,虽然可能内存大了 列车调度参考
可以改进之处可能就是(提前判断是否有一个数后面比他小的数不是倒序的,例如:1,2,3,4中1,4,2,3是无法构成栈混洗的,因为4后面的2,3均比它小而且顺序)

下图为思路图:

此处是代码

//#include "stdafx.h"
#include <cstdio>
using namespace std;
#define MAXL 1600000
struct mystack
{int n = 0;int sstack[MAXL];    void push(int a){n++;sstack[n] = a;}void pop(){n--;}int top(){return sstack[n];}bool empty(){if (n == 0){return true;}elsereturn false;}int size(){return n;}
};
mystack a, b, s;
int real[MAXL];
bool action[MAXL];
int main()
{int n, m;scanf("%d %d", &n, &m);for (int i = n; i >= 1; i--){a.push(i);}for (int i = 0; i < n; i++){scanf("%d", real + i);}int step = 0, numbertotal = 0;bool done = false;while (!done){if (numbertotal==n){done = true;break;}else if (s.empty()){s.push(a.top());a.pop();action[step] = true;}else if (s.top()==real[numbertotal]){b.push(s.top());s.pop();numbertotal++;action[step] = false;}else if (!a.empty()){s.push(a.top());a.pop();action[step] = true;}else{printf("No\n");break;}if (s.size() > m){printf("No\n");break;}step++;}if (done){for (int i = 0; i < step; i++){if (action[i])    printf("push\n");else printf("pop\n");}}return 0;
}

PA 2-2 真二叉树重构

描述
一般来说,给定二叉树的先序遍历序列和后序遍历序列,并不能确定唯一确定该二叉树。
(图一)比如图一中的两棵二叉树,虽然它们是不同二叉树,但是它们的先序、后序遍历序列都是相同的。但是对于“真二叉树”(每个内部节点都有两个孩子的二叉树),给定它的先序、后序遍历序列足以完全确定它的结构。将二叉树的n个节点用[1, n]内的整数进行编号,输入一棵真二叉树的先序、后序遍历序列,请输出它的中序遍历序列。
输入
第一行为一个整数n,即二叉树中节点的个数。
第二、三行为已知的先序、后序遍历序列。
输出
仅一行,给定真二叉树的中序遍历序列。
实际题目

大概递归思路,不过其实可以用栈的方式也能做(循环)… 就是没想完全这个方法,就是这个节点怎么去深入是一个问题。

//#include "stdafx.h"
#include<iostream>
#define L 4000000
using namespace std;struct node
{int data;node *lc, *rc;
};int pre_tree[L], post_tree[L];node *buildtree(int pre_l, int pre_h, int post_l, int post_h)
{node *root = new node;root->data = pre_tree[pre_l];//前序排序的左端顶点(即根节点)root->lc = root->rc = NULL;int pos = 0, number_sl = 0;if (post_l == post_h)    return root;//后面没有了即返回root    for (int i= post_l; i < post_h; i++){if (pre_tree[pre_l+1]==post_tree[i]){pos = i;//记录左子树的分界break;}}number_sl = pos - post_l + 1;    root->lc = buildtree(pre_l + 1, number_sl + pre_l, post_l, pos);root->rc = buildtree(pre_l + number_sl + 1, pre_h, pos + 1, post_h - 1);    return root;
}
void show_inoder(node *root)
{if (!root)    return;//root 不为空的时候一直走到左孩子的底端打印,随后走右孩子    show_inoder(root->lc);printf("%d ", root->data);show_inoder(root->rc);
}
int main()
{int n;scanf("%d", &n);for (int i = 0; i < n; i++)scanf("%d", pre_tree + i);for (int i = 0; i < n; i++)scanf("%d", post_tree + i);node *root = buildtree(0, n - 1, 0, n - 1);show_inoder(root);return 0;
}

PA2-3 旅行商(TSP)

描述
Shrek是一个大山里的邮递员,每天负责给所在地区的n个村庄派发信件。但杯具的是,由于道路狭窄,年久失修,村庄间的道路都只能单向通过,甚至有些村庄无法从任意一个村庄到达。这样我们只能希望尽可能多的村庄可以收到投递的信件。
Shrek希望知道如何选定一个村庄A作为起点(我们将他空投到该村庄),依次经过尽可能多的村庄,路途中的每个村庄都经过仅一次,最终到达终点村庄B,完成整个送信过程。这个任务交给你来完成。
输入
第一行包括两个整数n,m,分别表示村庄的个数以及可以通行的道路的数目。
以下共m行,每行用两个整数v1和v2表示一条道路,两个整数分别为道路连接的村庄号,道路的方向为从v1至v2,n个村庄编号为[1, n]。
输出
输出一个数字,表示符合条件的最长道路经过的村庄数。
实际题目

//#include "stdafx.h"
#include<iostream>
#define L 1000000
#define GetMax(a,b) a>b?a:b
using namespace std;
struct NNode
{int Psub;//下一个点的序号NNode* succ;//连接下下个的点信息(例如0->1 0->4,那么 1先进入front 后4进入front,1就成了succ的部分)
};struct PNode
{int in;//顶点的入度int len;//到达此点所需要经过的边长数NNode* front;//此点去往的点信息
};PNode List[L];
int stack[L];
int maxlen;
NNode *t;
void ToloSort(int n,int m)
{int top = 0;for (int k = 0; k < n; k++){if (!List[k].in){stack[++top] = k;}}while (top){//直到原先内部第一次入度为0的顶点都被访问了一遍int v = stack[top--];/* 此处用到了拓扑排序,for 入度为0的开始,访问前面的点信息,往后p为NULL结束for循环 */for (NNode* p = List[v].front; p; p = p->succ){//此处不是拓扑排序内容 仅用来记录来到这个点需要经过的边长List[p->Psub].len = GetMax(List[v].len + 1, List[p->Psub].len);//是入度为0的序号点+1 即这次走的路长,还是内部有的长maxlen = GetMax(List[p->Psub].len, maxlen);//更新更长的边数            /* 此处看不懂请参考书上的拓扑排序原理 DAG必有零点入度顶点的特性实现拓扑排序 */if (!(--List[p->Psub].in))//先进行相减操作操作后如果入度为0,弹出栈顶序号{stack[++top] = p->Psub;}}}
}
int main()
{int n, m;//题目的要求n,mscanf("%d %d", &n, &m);int tems, teme;for (int i = 0; i < m; i++){scanf("%d %d", &tems, &teme);tems--, teme--;//使点的序号按数组的要求从0开始表示t = new NNode;//新生成一个对象t->Psub = teme;List[teme].in++;//代表后面的点是有点入进来的t->succ = List[tems].front;//此处当front为空 即为NULL指针List[tems].front = t;//将下个点的序号,下下个点(直接连接)的信息传入}ToloSort(n, m);printf("%d\n", maxlen + 1);//经过的顶点数=边数+1return 0;
}

数据结构(上)总结:
对于C++也是学堂在线看到基础部分就跳到结构(上)来学,有些对于为什么一定生成新对象的做法还是有些疑惑,感觉如果自己单独只看课可能收获不会特别大,得带着题目和论坛(学堂在线的老版真的做的好,论坛直到现在都有人去回复,也能看到以前的帖子,那里面有很多大佬对一些课堂知识点的看法,也有老师提出的思考题的见解)

个人感觉最难的可能是没有适应无库编程吧,二叉树、链表和图的解法很多时候都是以递归形式,如果逻辑不理清很难写下去编程题,编程题极其有意思,希望各位不要只看答案,想不出来看看书,看看其他人代码,分析对比思路的不同会很有意思。

【学堂在线】清华数据结构 OJ小记录相关推荐

  1. 学堂在线:数据结构_邓俊辉(2020秋)——C++ 学习笔记

    Table of Contents 第一章 绪论 1.1 计算机与算法 1.2 复杂度度量 1.3 复杂度分析 1.4 递归与优化 习题 第二章 向量 第一章 绪论 1.1 计算机与算法 计算机科学核 ...

  2. 学堂在线_大数据机器学习_小笔记

    学堂在线大数据机器学习小笔记 20220607 - https://www.xuetangx.com/learn/THU08091001026/THU08091001026/10333105/vide ...

  3. python交互式程序设计导论小测验答案_最新网课答案2020学堂在线Python 交互式程序设计导论...

    最新网课答案2020学堂在线Python 交互式程序设计导论 更多相关问题 [填空题] 五代西蜀花鸟画的代表画家是(). [问答题,简答题] 明代插图版画主要有哪几个流派?各派的特点是什么? [填空题 ...

  4. 计算机编程导论python程序设计答案-学堂在线_计算机科学与Python编程导论_作业课后答案...

    学堂在线_计算机科学与Python编程导论_作业课后答案 答案: 更多相关问题 近代中国完全沦为半殖民地半封建社会的标志是:A.<马关条约>B.<辛丑条约>C.<凡尔赛和 ...

  5. 【学堂在线】C++ 语言程序设计基础 - 课程习题

    C++ 语言程序设计基础 - 学堂在线 第1章 绪论 第3章 函数 C3-1 直角三角形 C3-2 斐波那契数列 C3-3 丑数 第4章 类与对象 C4-1 最大公约数 C4-2 反转整数 C4-3 ...

  6. 国内慕课(学堂在线,华文慕课,网易公开课)

    慕课(MOOC)(MOOCs是MOOC的复数形式,意指多门MOOC),英文直译"大规模开放的在线课程(Massive Open OnlineCourse)",是新近涌现出来的一种在 ...

  7. Springboot校园在线打印预约系统小程序【纯干货分享,附源码91740】

    摘 要 本文设计了一种基于微信支付的校园在线打印预约系统小程序,系统为人们提供了方便快捷的线上打印服务,包括打印预约.注册登录.打印平台.校园资讯等,用户不仅能够方便快捷在线搜索打印方式.还能进行打印 ...

  8. python交互式程序设计导论答案第五周_学堂在线_计算机科学与Python编程导论_章节测试答案...

    学堂在线_计算机科学与Python编程导论_章节测试答案 更多相关问题 素描的三种表现形式是:(). 运行下列程序:Private Sub form_Click()For i = 1 To 2x = ...

  9. 神经网络学习小记录52——Pytorch搭建孪生神经网络(Siamese network)比较图片相似性

    神经网络学习小记录52--Pytorch搭建孪生神经网络(Siamese network)比较图片相似性 学习前言 什么是孪生神经网络 代码下载 孪生神经网络的实现思路 一.预测部分 1.主干网络介绍 ...

最新文章

  1. Asp.net支持的最大上传文件大小
  2. python5_python5
  3. 2013 vc 字体 静态文本框_vc 中mfc 的 静态文本框 的名字 的字体怎么设置
  4. 通过公网ip或域名下载自己的文件的一些思路
  5. r语言绘制精美pcoa图_R语言绘制交互式热图
  6. centos6.5 yum安装mysql_CentOS 6.5使用yum安装MySQL快速上手必备
  7. Python 函数的执行流程-函数递归-匿名函数-生成器
  8. 机器学习之tensorflow出现的一些问题
  9. 软工作业:(2)硬币游戏--代码分析与改进
  10. [APM] 解读APM技术分类和实现方式
  11. 设置时区,时间,日期的脚本
  12. 分享Qt的面试题目(或许未来的我能用的上呢)
  13. NYOJ74 - 小学生算术
  14. Delphi Form Designer (窗体设计器)之一
  15. 开发你自己的XMPP 续 - Openfire 插件开发
  16. brace源码改造实现跨服务器监控-zjs
  17. 百度云网盘批量复制文件,在线复制到每个文件夹中PC版
  18. 2022年上半年5月网络工程师试题及答案
  19. 如何在视频中添加水印?给视频添加水印方法
  20. POJ 1723 士兵排队 C语言实现

热门文章

  1. Android好用的第三方开源库
  2. hdu-1878欧拉回路
  3. quarkus数据库篇之一:比官方demo更简单的基础操作
  4. 西行漫记(2):上课第一天
  5. 英语四级报名图片可以计算机,英语四级报名_实用电脑小技巧:照片制作成标准的一寸照或二寸_沪江英语...
  6. Windows Server 2008 R2安装教程
  7. stc8a-22.1184-bu 步。。。。进。、电。额。机
  8. vc6.0静态链接库的创建与使用方法
  9. 高通平台 lcd driver 调试小结
  10. Python爬虫实战 - 电影榜单Top250