《串并行数据结构与算法(SML语言)实验》题解
注意:本题解仅供参考学习,请勿直接抄袭代码,否则造成的后果和笔者无关。
第一题:
题意:
对n个数升序排序。
题解:
快排,不解释。
代码(省略了输入输出函数,下同):
val n = getInt ();
val l = getIntTable (n);
fun qsort [] = []
| qsort l' = let
val p = hd l';
val l1 = List.filter (fn x => x < p) l';
val l2 = List.filter (fn x => x = p) l';
val l3 = List.filter (fn x => x > p) l';
in qsort(l1) @ l2 @ qsort(l3) end;
printIntTable (qsort l);
第二题:
题意:
单源最短路,点数1000以内,边数3000以内。
题解:
实在想不出SML语言怎么写邻接表,考虑到点数只有1000,所以直接用邻接矩阵,既然如此,优先队列优化也不带了,O(n2)水过。
代码:
val inf = 0x3fffffff;
val n = getInt() and m = getInt() and s = getInt() - ;
val g = Array2.array (n, n, inf); (* 邻接矩阵 *)
List.tabulate (n, fn x => Array2.update (g, x, x, ));
fun read _ = let
val a = getInt() - and b = getInt() - and c = getInt();
val c1 = Int.min (c, Array2.sub (g, a, b));
val c2 = Int.min (c, Array2.sub (g, b, a));
val t1 = Array2.update (g, a, b, c1);
val t2 = Array2.update (g, b, a, c2);
in end;
List.tabulate (m, read);
val d = Array.array (n, inf); (* 其他点到源点距离 *)
val v = Array.array (n, false); (* 该点是否已访问 *)
Array.update(d, s, );
fun relax _ = let
val (m, u) = Array.foldli
(fn (i, a, (m, u)) => if (not (Array.sub (v, i))) andalso a < m then (a, i)
else (m, u))
(inf, ~)
d; (* 寻找d中最小的值 *)
in if u <> ~ then let
val t0 = Array.update(v, u, true);
val t1 = Vector.foldli
(fn (i, a, _) => if a <> inf andalso m + a < Array.sub(d, i) then Array.update(d, i, m + a) (* 寻找能松弛的边(d[v] > d[u] + e(u, v)) *)
else ())
()
(Array2.row (g, u));
in end else end;
List.tabulate (n, relax);
val out = Array.foldr (op ::) [] d; (* Array转List *)
printIntTable (map (fn x => if x = inf then ~ else x) out);
第三题:
题意:
寻找括号序列中最长的闭合字串(闭合就是满足串内所有括号匹配且最外面由括号包裹)。
题解:
维护一个栈存储当前待匹配左括号出现的位置,每当出现一个右括号且栈不为空则用这个右括号和栈顶左括号的距离更新最大值,并让栈顶出栈。不过该算法是串行的,并行我想不出来。
代码:
val n = getInt ();
val a = ListPair.zip (List.tabulate (n, fn x => x), getIntTable n); (* 将读入的List和索引zip在一起 *)
fun calc ((i, x), (st, m)) = (* i是当前的位置,x表示当前是左还是右括号,st是栈,m是当前的最大值 *)
if x = then (i::st, m) else
if st = [] then (st, m) else let
val h = hd st;
val tm = Int.max (m, i - h + );
in (tl st, tm) end;
val ans = # (foldl calc ([], ) a);
printInt ans;
第四题:
题意:
水平坐标轴上有n个楼房,每个楼房都有一个高度,且可能相互覆盖,要求求出这些楼房的轮廓线(即每一“段”的高度)。
题解:
首先将高度离散化(按照大小映射到0,1,2……n),然后将楼房的左边界和右边界一起排序,同时维护一个串,每当遇到一个边界则让该串0到边界高度(离散化后)的元素+1(左边界)或-1(右边界),并查询修改后该串最大的不是0的元素的位置对应的高度和修改前该串最大的不是0的元素的位置对应的高度比较,如果不一样则输出。对这个串的修改和查询因为是区间修改和查询,我感觉需要用线段树,事实上这道题的通用版本(不在水平坐标轴上)确实只能用线段树,但是这道题因为区间修改查询的左端点都是0,所以可能O(nlogn)还有别的方法,我想不出。不过既然出题人给我们放宽了要求,所以用O(n2)应该也能过,于是我就在遇到边界时就直接在串里边界高度(离散化后)的单个元素+1或-1,并维护一个离散化高度的最大值,更新时如果当前是右边界且-1后离散化高度的最大值会改变则往左再查找,这一步会花O(n),不过也省去了线段树大量的代码。
代码:
fun sort f [] = [] | sort f (h :: a) = let
val a1 = List.filter (fn x => f (x, h)) a;
val a2 = List.filter (fn x => not (f (x, h))) a;
in (sort f a1) @ [h] @ (sort f a2) end; (* 泛型排序函数 *)
val n = getInt();
fun read _ = let
val a = getInt() and b = getInt() and c = getInt();
in (a, b, c) end;
val reada = List.tabulate (n, read);
val sorta = sort (fn (x, y) => (# x) < (# y)) reada; (* 按高度排序 *)
val vechei = Vector.fromList (List.map (fn x => (# x)) sorta); (* 将高度映射到离散化的数 *)
val aa = ListPair.map
(fn (x, (y, _, z)) => (y, x, z))
(List.tabulate (n, fn x => x), sorta);
fun f ([]) = [] | f (x :: y: (int * int * int) list) = (# x, # x, ) :: (# x, # x, ) :: f (y);
val borda = sort (fn (x, y) => (# x) < (# y)) (f aa); (* 将边界排序 *)
val hei = Array.array(n, );
val m = Array.array(, ~);
fun f2 (a, b, c) =
if c = then let
val t1 = Array.update (hei, b, (Array.sub (hei, b)) + );
val tm = Array.sub (m, );
val t2 = if Array.sub (hei, b) = then
if b > tm then let (* 如果左边界更新后大于原来的最大值 *)
val t3 = if tm = ~ orelse
(Vector.sub (vechei, b)) <> (Vector.sub (vechei, tm)) then let
val t5 = printIntTable [a, Vector.sub (vechei, b)];
val t6 = print ("\n");
in () end else ();
val t4 = Array.update (m, , b);
in () end else ()
else ()
in () end else let
val t1 = Array.update (hei, b, (Array.sub (hei, b)) - );
val t2 = if Array.sub (hei, b) = then
if b = Array.sub (m, ) then let (* 如果待更新的值等于最大值(即更新后最大值会减小) *)
fun find ~ = ~
| find i = if (Array.sub (hei, i)) > then i else find (i - );
val t3 = Array.update (m, , find b);
val tm = Array.sub (m, );
val t4 = if tm = ~ then let
val t5 = printIntTable [a, ];
val t6 = print ("\n");
in () end else
if (Vector.sub (vechei, b)) <> (Vector.sub (vechei, tm)) then let
val t5 = printIntTable [a, Vector.sub (vechei, tm)];
val t6 = print ("\n");
in () end else ();
in () end else ()
else ()
in () end;
List.app f2 borda;
第五题:
题意:
给定一个括号序列,判断它是否是匹配的。
题解:
把左括号看作+1,右括号看作-1,只要所有前缀和都大于0,最后总和等于0即可。这个是串行算法,我没想出并行算法怎么保证Work为n。
代码:
val n = getInt();
val l = getIntTable n;
fun calc (x, (f, sum)) =
if not f then (f, sum) else
if x = then (f, sum + ) else
if sum = then (false, sum) else (f, sum - );
val (a, b) = List.foldl calc (true, ) l;
if a andalso b = then printInt else printInt ;
第六题:
题意:
高精度加、减、乘,不给用IntInf。
题解:
类似小学列竖式不解释。注意要小心前导0,对操作数首先要清一次前导0,减法的结果当然要清一次,关键是乘法的结果也要清,防止因为0乘导致结果为0的情况。
代码:
fun clear0 [] = [] | clear0 l = if hd l = then clear0 (tl l) else l;
val n1 = getInt ();
val num1 = List.rev (clear0 (getIntTable n1));
val n2 = getInt ();
val num2 = List.rev (clear0 (getIntTable n2));
fun plus (c, (a, b, [])) =
((a + c) div , ((a + c) mod ) :: b, [])
| plus (c, (a, b, x :: l)) =
((a + x + c) div , ((a + x + c) mod ) :: b, l);
val (a1, b1, _) = List.foldl plus (, [], num2) num1;
if a1 > then printIntTable (a1 :: b1) else printIntTable b1;
printEndOfLine (); fun minus (c, (a, b, [])) =
if c - a < then
(, ( + c - a) :: b, [])
else (, (c - a) :: b, [])
| minus (c, (a, b, x :: l)) =
if c - x - a < then
(, ( + c - x - a) :: b, l)
else (, (c - x - a) :: b, l);
val (_, b2, _) = List.foldl minus (, [], num2) num1;
printIntTable (clear0 b2);
printEndOfLine (); fun mul1D ((i, x), y) = let
fun mul2D (c, (a, b)) = ((a + c * x) div , ((a + c * x) mod ) :: b);
val (a3, b3) = List.foldl mul2D (, []) num1;
val c3 = List.rev ((if a3 > then a3 :: b3 else b3)
@ List.tabulate (i, fn x => )); (* 第二个操作数第i位乘第一个操作数之后要补i个0 *)
val (a4, b4, _) = List.foldl plus (, [], List.rev y) c3;
in if a4 > then a4 :: b4 else b4 end;
printIntTable (clear0 (List.foldl mul1D []
(ListPair.zip (List.tabulate (n2, fn x => x), num2))));
第七题:
题意:
求无向图的割点和桥(割边)。
题解:
Tarjan算法。我用Array套List实现邻接表,但是效率我有点不明,另外用大小为1的Array模拟可变变量是真的爽。
代码:
val n = getInt() and m = getInt();
val g : (int * int) list array = Array.array (n, []);
fun reade i = let
val a = getInt() - and b = getInt() - ;
val t1 = Array.update(g, a, (b, i) :: (Array.sub (g, a)));
val t2 = Array.update(g, b, (a, i) :: (Array.sub (g, b)));
in end;
List.tabulate (m, reade);
val cp = Array.array (n, false); (* 某点是否为割点 *)
val ce = Array.array (m, false); (* 某边是否为桥 *)
val dfn = Array.array (n, );
val low = Array.array (n, );
val cnt = Array.array (, ); fun tarjan fa x = let
val num = Array.sub (cnt, );
val t1 = Array.update (cnt, , num + );
val t2 = Array.update (dfn, x, num);
val t3 = Array.update (low, x, num);
val ch = Array.array (, );
fun calc (i, j) =
if (Array.sub (dfn, i)) = then let
val t1 = Array.update (ch, , (Array.sub (ch, )) + );
val t2 = tarjan x i;
val t3 = Array.update (low, x,
Int.min(Array.sub (low, x), Array.sub (low, i)));
val t4 = if x = andalso (Array.sub (ch, )) > then
(Array.update (cp, x, true)) else ();
val t5 = if x <> andalso (Array.sub (dfn, x)) <= (Array.sub (low, i)) then
(Array.update (cp, x, true)) else ();
val t6 = if (Array.sub (dfn, x)) < (Array.sub (low, i)) then
(Array.update (ce, j, true)) else ();
in () end else
if i <> fa then
Array.update (low, x, Int.min(Array.sub (low, x), Array.sub (dfn, i)))
else ();
val t4 = List.app calc (Array.sub (g, x));
in () end; tarjan ~ ;
printInt (Array.foldl (fn (x, y) => if x then y + else y) cp);
printInt (Array.foldl (fn (x, y) => if x then y + else y) ce);
第八题
题意:
多次询问串中的区间最大值。串大小1000以内,询问次数5000以内。(RMQ问题)
题解:
正解当然是O(nlogn)的倍增,不过串大小1000以内,所以直接开了个O(n2)的数组,预处理所有区间的最大值,然后询问就直接在数组中查询。
代码:
val n = getInt() and m = getInt();
val l = ListPair.zip(List.tabulate (n, (fn x => x)), getIntTable n);
val a = Array2.array(n, n, );
fun f i = let
val cl = List.drop (l, i);
val t1 = Array2.update(a, i, i, # (hd cl));
val t = List.app (fn (x, y) =>
Array2.update(a, i, x, Int.max (Array2.sub(a, i, x - ), y))) (tl cl);
in end;
List.tabulate (n, f);
fun q _ = let
val l = getInt() - and r = getInt() - ;
in printInt (Array2.sub(a, l, r)) end;
List.tabulate (m, q);
第九题:
题意:
判断质数。待判断的数非常大,差不多有40位。
题解:
朴素法T了,学习了Miller-Rabin算法,对于已知的n个素数,利用费马小定理和二次探测定理对待判断的数进行判定,判定失误的概率为4-n,复杂度大概为O(nlogp)吧,n为已知素数的个数,p为待判断的数。
代码:
val n = getIntInf();
val t: IntInf.int list = [, , , , , , , , , , , , , , , , ,
, , , , , , , ];
if (List.exists (fn x => x = n) t) then printString "True" else let
fun pow (a: IntInf.int, b: IntInf.int, c: IntInf.int) =
case b of
=>
| => a mod c
|otherwise => let
val d = pow (a, b div , c);
in (if b mod = then d * d mod c else d * d * a mod c) end;
val pm1 = n - ;
fun f1 (x: IntInf.int, cnt) =
if x mod = then (f1 (x div , cnt + )) else (x, cnt);
val (base, k) = f1 (pm1, );
fun f2 (test: IntInf.int, flag) = if not flag then false else let
val pbase = pow (test, base, n);
fun f3 (i, (r, aa: IntInf.int)) =
if not r then (r, aa) else let
val rnext = aa * aa mod n;
val rr = not (rnext = andalso aa <> andalso aa <> n - );
val ra = rnext;
in (rr, ra) end;
val (r, a) = List.foldl f3 (true, pbase) (List.tabulate (k, fn x => x));
in r andalso a = end;
in (if List.foldl f2 true t then printString "True" else printString "False") end;
《串并行数据结构与算法(SML语言)实验》题解的更多相关文章
- 数据结构1:数据结构与算法C语言版分析概述
本节开始将带领大家系统地学习数据结构,作为一门计算机专业大二学生的必修课程,该课程面对的目标人群为初步具备基本编程能力和编程思想的程序员(大一接触了 C 语言或者 C++).通过系统地学习数据结构,可 ...
- 数据结构与算法C语言实现笔记(1)--表
声明:此一系列博客为阅读<数据结构与算法分析--C语言描述>(Mark Allen Weiss)笔记,部分内容参考自网络:转载请注明出处. 1.表 表是最简单的数据结构,是形如A1.A2. ...
- 数据结构与算法 Python语言实现 第一章练习
说明:部分代码参考了Harrytsz的文章:https://blog.csdn.net/Harrytsz/article/details/86645857 巩固 R-1.1 编写一个Python函数 ...
- 《数据结构与算法(C语言版)》严蔚敏 | 第五章 建立二叉树,并完成三/四种遍历算法
PS:所有的代码示例使用的都是这个图 2019-10-29 利用p126的算法5.3建立二叉树,并完成三种遍历算法 中序 后序 先序 #include<iostream> #include ...
- 《数据结构与算法Python语言描述》习题第二章第三题(python版)
ADT Rational: #定义有理数的抽象数据类型 Rational(self, int num, int den) #构造有理数num/den +(self, Rational r2) #求出本 ...
- 《数据结构与算法Python语言描述》习题第二章第二题(python版)
ADT Date: #定义日期对象的抽象数据类型 Date(self, int year, int month, int day) #构造表示year/month/day的对象 difference( ...
- 《数据结构与算法Python语言描述》习题第二章第一题(python版)
题目:定义一个表示时间的类Timea)Time(hours,minutes,seconds)创建一个时间对象:b)t.hours(),t.minutes(),t.seconds()分别返回时间对象t的 ...
- 数据结构与算法C语言所有头文件汇总 —— 持续更新
header.h // 顺序表的结构定义 #define Maxsize 100 //const int Maxsize = 100; // 预先定义一个足够大的常数 typedef struct { ...
- 《数据结构与算法(C语言版)》严蔚敏 | 第四章课本案例
//二叉树的顺序存储表示 #define MAXTSIZE 100 typedef TElemtype SqBiTree[MAXTSIZE]; SqBiTree bt; //二叉树的二叉链表存储表示 ...
随机推荐
- (二)JavaMail创建包含内嵌图片的邮件
链接:https://blog.csdn.net/qq_41151659/article/details/96475739 代码如下: import com.sun.mail.util.MailSSL ...
- ZWave 数据包格式
ZWave Device 的过程中,其实就是对不同的 COMMAND CLASS 进行解析处理.在刚开始进入ZWAVE 开发时,为了弄清楚数据包的格式,做了下面的参考表格.不过后来发现用来抓包的 sn ...
- Android笔记布局资源文件
在项目的res--layout目录下的文件叫布局资源文件,用于控制页面的布局显示 在Java代码中引用布局资源我们已经很熟悉了. setContentView(R.layout.activity_ma ...
- cb20a_c++_string类型的查找
cb20a_c++_string类型的查找s.find(args) //精确匹配,顺序查找, abc, 连续的包含在abcde,或者fabcde;s.rfind(args) //精确匹配.反向查找s. ...
- js银行卡四个数字一个空格
!function () { document.getElementById('bankCard').onkeyup = function (event) { var v = this.value; ...
- 虚拟机 VMware 设置VMWARE通过桥接方式使用主机无线网卡上网
环境:WIN7旗舰版,台式机,U盘无线上网卡. 虚拟软件:VMware9.0,虚拟系统:CentOS6.4 需要实现虚拟机以独立机形式工作和上网. 先介绍一下VMware网络设置的三种方式 1 Hos ...
- 谈谈 Promise 以及实现 Fetch 的思路
Promise 是异步编程的一种解决方案. Promise /** * 属性 */ Promise.length Promise.prototype /** * 方法 */ Promise.all(i ...
- Spring Cloud Alibaba系列(五)sentinel实现服务限流降级
一.sentinel是什么 sentinel的官方名称叫分布式系统的流量防卫兵.Sentinel 以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护服务的稳定性.在Spring Clou ...
- 【实践】如何利用tensorflow的object_detection api开源框架训练基于自己数据集的模型(Windows10系统)
如何利用tensorflow的object_detection api开源框架训练基于自己数据集的模型(Windows10系统) 一.环境配置 1. Python3.7.x(注:我用的是3.7.3.安 ...
- Spring 容器的初始化
读完这篇文章你将会收获到 了解到 Spring 容器初始化流程 ThreadLocal 在 Spring 中的最佳实践 面试中回答 Spring 容器初始化流程 引言 我们先从一个简单常见的代码入手分 ...