当前位置:首页 » 操作系统 » 算法案例抽

算法案例抽

发布时间: 2023-02-27 04:04:21

A. 如何实现抽签算法

首先,你的数据库的user表需要存储报名人的id,是否参加第一次抽签(first)第一次抽签是否抽中(first_row),是否参加第一次抽签(second),第二次抽签是否抽中(second_row),和报名人的基本信息(name,password......)。

然后进行报名注册(报名的同时first=1,second=0),当第一次报名时间截止,如果第一次报名人数超过50人时抽签,被抽到的人first_row=1。

然后进行第二次报名注册,第一次没有抽中的人(second_row==0)登录时可以选择是否报名(second=1),当第二次报名时间截止,所有second==1的用户抽签,抽中者second_row=1。

B. 什么是算法,都什么,举个例子,谢谢

根据我个人的理解:
算法就是解决问题的具体的方法和步骤,所以具有以下性质:

1、有穷性: 一个算法必须保证执行有限步之后结束(如果步骤无限,问题就无法解决)
2、确切性:步骤必须明确,说清楚做什么。
3、输入:即解决问题前我们所掌握的条件。
4、输出:输出即我们需要得到的答案。
5、可行性:逻辑不能错误,步骤必须有限,必须得到结果。

算法通俗的讲:就是解决问题的方法和步骤。在计算机发明之前便已经存在。只不过在计算机发明后,其应用变得更为广泛。通过简单的算法,利用电脑的计算速度,可以让问题变得简单。

譬如:计算 1×2×3×4。。。。×999999999×1000000000
如果人为计算,可想而知,即使你用N卡车的纸张都很难计算出来,即使算出来了,也很难保证其准确性。
如果用VB算法:
dim a as integer
a=1
For i =1 to 1000000000
a=a*i
next i
input a
就这样,简单的算法,通过计算机强大的计算能力,问题就解决了。
关于这段算法的解释:i每乘一次,其数值都会增大1,一直乘到1000000000,这样,就将从1到1000000000的每个数都乘了。而且每乘一次,就将结束赋给a,这样,a就代表了前面的相乘的所有结果,一直乘到1000000000。最后得到的a,就是我们想要的。

〓以下是网络复制过来的,如果你有足够耐心,可以参考一下。

算法(Algorithm)是一系列解决问题的清晰指令,也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。
算法可以理解为有基本运算及规定的运算顺序所构成的完整的解题步骤。或者看成按照要求设计好的有限的确切的计算序列,并且这样的步骤和序列可以解决一类问题。
一个算法应该具有以下五个重要的特征:
1、有穷性: 一个算法必须保证执行有限步之后结束;
2、确切性: 算法的每一步骤必须有确切的定义;
3、输入:一个算法有0个或多个输入,以刻画运算对象的初始情况,所谓0个输入是指算法本身定除了初始条件;
4、输出:一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输出的算法是毫无意义的;
5、可行性: 算法原则上能够精确地运行,而且人们用笔和纸做有限次运算后即可完成。
计算机科学家尼克劳斯-沃思曾着过一本着名的书《数据结构十算法= 程序》,可见算法在计算机科学界与计算机应用界的地位。
[编辑本段]算法的复杂度
同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。算法分析的目的在于选择合适算法和改进算法。一个算法的评价主要从时间复杂度和空间复杂度来考虑。
时间复杂度
算法的时间复杂度是指算法需要消耗的时间资源。一般来说,计算机算法是问题规模n 的函数f(n),算法的时间复杂度也因此记做
T(n)=Ο(f(n))
因此,问题的规模n 越大,算法执行的时间的增长率与f(n) 的增长率正相关,称作渐进时间复杂度(Asymptotic Time Complexity)。
空间复杂度
算法的空间复杂度是指算法需要消耗的空间资源。其计算和表示方法与时间复杂度类似,一般都用复杂度的渐近性来表示。同时间复杂度相比,空间复杂度的分析要简单得多。
详见网络词条"算法复杂度"
[编辑本段]算法设计与分析的基本方法
1.递推法
递推法是利用问题本身所具有的一种递推关系求问题解的一种方法。它把问题分成若干步,找出相邻几步的关系,从而达到目的,此方法称为递推法。
2.递归
递归指的是一个过程:函数不断引用自身,直到引用的对象已知
3.穷举搜索法
穷举搜索法是对可能是解的众多候选解按某种顺序进行逐一枚举和检验,并从众找出那些符合要求的候选解作为问题的解。
4.贪婪法
贪婪法是一种不追求最优解,只希望得到较为满意解的方法。贪婪法一般可以快速得到满意的解,因为它省去了为找最优解要穷尽所有可能而必须耗费的大量时间。贪婪法常以当前情况为基础作最优选择,而不考虑各种可能的整体情况,所以贪婪法不要回溯。
5.分治法
把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
6.动态规划法
动态规划是一种在数学和计算机科学中使用的,用于求解包含重叠子问题的最优化问题的方法。其基本思想是,将原问题分解为相似的子问题,在求解的过程中通过子问题的解求出原问题的解。动态规划的思想是多种算法的基础,被广泛应用于计算机科学和工程领域。
7.迭代法
迭代是数值分析中通过从一个初始估计出发寻找一系列近似解来解决问题(一般是解方程或者方程组)的过程,为实现这一过程所使用的方法统称为迭代法。
[编辑本段]算法分类
算法可大致分为基本算法、数据结构的算法、数论与代数算法、计算几何的算法、图论的算法、动态规划以及数值分析、加密算法、排序算法、检索算法、随机化算法、并行算法。
[编辑本段]举例
经典的算法有很多,如:"欧几里德算法"。
[编辑本段]算法经典专着
目前市面上有许多论述算法的书籍,其中最着名的便是《计算机程序设计艺术》(The Art Of Computer Programming) 以及《算法导论》(Introction To Algorithms)。
[编辑本段]算法的历史
“算法”即算法的大陆中文名称出自《周髀算经》;而英文名称Algorithm 来自于9世纪波斯数学家al-Khwarizmi,因为al-Khwarizmi在数学上提出了算法这个概念。“算法”原为"algorism",意思是阿拉伯数字的运算法则,在18世纪演变为"algorithm"。欧几里得算法被人们认为是史上第一个算法。 第一次编写程序是Ada Byron于1842年为巴贝奇分析机编写求解解伯努利方程的程序,因此Ada Byron被大多数人认为是世界上第一位程序员。因为查尔斯·巴贝奇(Charles Babbage)未能完成他的巴贝奇分析机,这个算法未能在巴贝奇分析机上执行。 因为"well-defined procere"缺少数学上精确的定义,19世纪和20世纪早期的数学家、逻辑学家在定义算法上出现了困难。20世纪的英国数学家图灵提出了着名的图灵论题,并提出一种假想的计算机的抽象模型,这个模型被称为图灵机。图灵机的出现解决了算法定义的难题,图灵的思想对算法的发展起到了重要作用的。

C. hadoop的maprece常见算法案例有几种

基本MapRece模式

计数与求和
问题陈述:
有许多文档,每个文档都有一些字段组成。需要计算出每个字段在所有文档中的出现次数或者这些字段的其他什么统计值。例如,给定一个log文件,其中的每条记录都包含一个响应时间,需要计算出平均响应时间。
解决方案:
让我们先从简单的例子入手。在下面的代码片段里,Mapper每遇到指定词就把频次记1,Recer一个个遍历这些词的集合然后把他们的频次加和。

1 class Mapper
2 method Map(docid id, doc d)
3 for all term t in doc d do
4 Emit(term t, count 1)
5
6 class Recer
7 method Rece(term t, counts [c1, c2,...])
8 sum = 0
9 for all count c in [c1, c2,...] do
10 sum = sum + c
11 Emit(term t, count sum)

这种方法的缺点显而易见,Mapper提交了太多无意义的计数。它完全可以通过先对每个文档中的词进行计数从而减少传递给Recer的数据量:

1 class Mapper
2 method Map(docid id, doc d)
3 H = new AssociativeArray
4 for all term t in doc d do
5 H{t} = H{t} + 1
6 for all term t in H do
7 Emit(term t, count H{t})

如果要累计计数的的不只是单个文档中的内容,还包括了一个Mapper节点处理的所有文档,那就要用到Combiner了:

1 class Mapper
2 method Map(docid id, doc d)
3 for all term t in doc d do
4 Emit(term t, count 1)
5
6 class Combiner
7 method Combine(term t, [c1, c2,...])
8 sum = 0
9 for all count c in [c1, c2,...] do
10 sum = sum + c
11 Emit(term t, count sum)
12
13 class Recer
14 method Rece(term t, counts [c1, c2,...])
15 sum = 0
16 for all count c in [c1, c2,...] do
17 sum = sum + c
18 Emit(term t, count sum)

应用:Log 分析, 数据查询

整理归类

问题陈述:
有一系列条目,每个条目都有几个属性,要把具有同一属性值的条目都保存在一个文件里,或者把条目按照属性值分组。 最典型的应用是倒排索引。
解决方案:
解决方案很简单。 在 Mapper 中以每个条目的所需属性值作为 key,其本身作为值传递给 Recer。 Recer 取得按照属性值分组的条目,然后可以处理或者保存。如果是在构建倒排索引,那么 每个条目相当于一个词而属性值就是词所在的文档ID。
应用:倒排索引, ETL
过滤 (文本查找),解析和校验
问题陈述:
假设有很多条记录,需要从其中找出满足某个条件的所有记录,或者将每条记录传换成另外一种形式(转换操作相对于各条记录独立,即对一条记录的操作与其他记录无关)。像文本解析、特定值抽取、格式转换等都属于后一种用例。
解决方案:
非常简单,在Mapper 里逐条进行操作,输出需要的值或转换后的形式。
应用:日志分析,数据查询,ETL,数据校验

分布式任务执行

问题陈述:
大型计算可以分解为多个部分分别进行然后合并各个计算的结果以获得最终结果。
解决方案: 将数据切分成多份作为每个 Mapper 的输入,每个Mapper处理一份数据,执行同样的运算,产生结果,Recer把多个Mapper的结果组合成一个。
案例研究: 数字通信系统模拟
像 WiMAX 这样的数字通信模拟软件通过系统模型来传输大量的随机数据,然后计算传输中的错误几率。 每个 Mapper 处理样本 1/N 的数据,计算出这部分数据的错误率,然后在 Recer 里计算平均错误率。
应用:工程模拟,数字分析,性能测试
排序
问题陈述:
有许多条记录,需要按照某种规则将所有记录排序或是按照顺序来处理记录。
解决方案: 简单排序很好办 – Mappers 将待排序的属性值为键,整条记录为值输出。 不过实际应用中的排序要更加巧妙一点, 这就是它之所以被称为MapRece 核心的原因(“核心”是说排序?因为证明Hadoop计算能力的实验是大数据排序?还是说Hadoop的处理过程中对key排序的环节?)。在实践中,常用组合键来实现二次排序和分组。
MapRece 最初只能够对键排序, 但是也有技术利用可以利用Hadoop 的特性来实现按值排序。想了解的话可以看这篇博客。
按照BigTable的概念,使用 MapRece来对最初数据而非中间数据排序,也即保持数据的有序状态更有好处,必须注意这一点。换句话说,在数据插入时排序一次要比在每次查询数据的时候排序更高效。
应用:ETL,数据分析

非基本 MapRece 模式

迭代消息传递 (图处理)

问题陈述:
假设一个实体网络,实体之间存在着关系。 需要按照与它比邻的其他实体的属性计算出一个状态。这个状态可以表现为它和其它节点之间的距离, 存在特定属性的邻接点的迹象, 邻域密度特征等等。
解决方案:
网络存储为系列节点的结合,每个节点包含有其所有邻接点ID的列表。按照这个概念,MapRece 迭代进行,每次迭代中每个节点都发消息给它的邻接点。邻接点根据接收到的信息更新自己的状态。当满足了某些条件的时候迭代停止,如达到了最大迭代次数(网络半径)或两次连续的迭代几乎没有状态改变。从技术上来看,Mapper 以每个邻接点的ID为键发出信息,所有的信息都会按照接受节点分组,recer 就能够重算各节点的状态然后更新那些状态改变了的节点。下面展示了这个算法:

1 class Mapper
2 method Map(id n, object N)
3 Emit(id n, object N)
4 for all id m in N.OutgoingRelations do
5 Emit(id m, message getMessage(N))
6
7 class Recer
8 method Rece(id m, [s1, s2,...])
9 M = null
10 messages = []
11 for all s in [s1, s2,...] do
12 if IsObject(s) then
13 M = s
14 else // s is a message
15 messages.add(s)
16 M.State = calculateState(messages)
17 Emit(id m, item M)

一个节点的状态可以迅速的沿着网络传全网,那些被感染了的节点又去感染它们的邻居,整个过程就像下面的图示一样:

案例研究: 沿分类树的有效性传递
问题陈述:
这个问题来自于真实的电子商务应用。将各种货物分类,这些类别可以组成一个树形结构,比较大的分类(像男人、女人、儿童)可以再分出小分类(像男裤或女装),直到不能再分为止(像男式蓝色牛仔裤)。这些不能再分的基层类别可以是有效(这个类别包含有货品)或者已无效的(没有属于这个分类的货品)。如果一个分类至少含有一个有效的子分类那么认为这个分类也是有效的。我们需要在已知一些基层分类有效的情况下找出分类树上所有有效的分类。
解决方案:
这个问题可以用上一节提到的框架来解决。我们咋下面定义了名为 getMessage和 calculateState 的方法:

1 class N
2 State in {True = 2, False = 1, null = 0},
3 initialized 1 or 2 for end-of-line categories, 0 otherwise
4 method getMessage(object N)
5 return N.State
6 method calculateState(state s, data [d1, d2,...])
7 return max( [d1, d2,...] )

案例研究:广度优先搜索
问题陈述:需要计算出一个图结构中某一个节点到其它所有节点的距离。
解决方案: Source源节点给所有邻接点发出值为0的信号,邻接点把收到的信号再转发给自己的邻接点,每转发一次就对信号值加1:

1 class N
2 State is distance,
3 initialized 0 for source node, INFINITY for all other nodes
4 method getMessage(N)
5 return N.State + 1
6 method calculateState(state s, data [d1, d2,...])
7 min( [d1, d2,...] )

案例研究:网页排名和 Mapper 端数据聚合
这个算法由Google提出,使用权威的PageRank算法,通过连接到一个网页的其他网页来计算网页的相关性。真实算法是相当复杂的,但是核心思想是权重可以传播,也即通过一个节点的各联接节点的权重的均值来计算节点自身的权重。

1 class N
2 State is PageRank
3 method getMessage(object N)
4 return N.State / N.OutgoingRelations.size()
5 method calculateState(state s, data [d1, d2,...])
6 return ( sum([d1, d2,...]) )

要指出的是上面用一个数值来作为评分实际上是一种简化,在实际情况下,我们需要在Mapper端来进行聚合计算得出这个值。下面的代码片段展示了这个改变后的逻辑 (针对于 PageRank 算法):

1 class Mapper
2 method Initialize
3 H = new AssociativeArray
4 method Map(id n, object N)
5 p = N.PageRank / N.OutgoingRelations.size()
6 Emit(id n, object N)
7 for all id m in N.OutgoingRelations do
8 H{m} = H{m} + p
9 method Close
10 for all id n in H do
11 Emit(id n, value H{n})
12
13 class Recer
14 method Rece(id m, [s1, s2,...])
15 M = null
16 p = 0
17 for all s in [s1, s2,...] do
18 if IsObject(s) then
19 M = s
20 else
21 p = p + s
22 M.PageRank = p
23 Emit(id m, item M)

应用:图分析,网页索引

值去重 (对唯一项计数)
问题陈述: 记录包含值域F和值域 G,要分别统计相同G值的记录中不同的F值的数目 (相当于按照 G分组).
这个问题可以推而广之应用于分面搜索(某些电子商务网站称之为Narrow Search)
Record 1: F=1, G={a, b}
Record 2: F=2, G={a, d, e}
Record 3: F=1, G={b}
Record 4: F=3, G={a, b}

Result:
a -> 3 // F=1, F=2, F=3
b -> 2 // F=1, F=3
d -> 1 // F=2
e -> 1 // F=2

解决方案 I:
第一种方法是分两个阶段来解决这个问题。第一阶段在Mapper中使用F和G组成一个复合值对,然后在Recer中输出每个值对,目的是为了保证F值的唯一性。在第二阶段,再将值对按照G值来分组计算每组中的条目数。
第一阶段:

1 class Mapper
2 method Map(null, record [value f, categories [g1, g2,...]])
3 for all category g in [g1, g2,...]
4 Emit(record [g, f], count 1)
5
6 class Recer
7 method Rece(record [g, f], counts [n1, n2, ...])
8 Emit(record [g, f], null )

第二阶段:

1 class Mapper
2 method Map(record [f, g], null)
3 Emit(value g, count 1)
4
5 class Recer
6 method Rece(value g, counts [n1, n2,...])
7 Emit(value g, sum( [n1, n2,...] ) )

解决方案 II:
第二种方法只需要一次MapRece 即可实现,但扩展性不强。算法很简单-Mapper 输出值和分类,在Recer里为每个值对应的分类去重然后给每个所属的分类计数加1,最后再在Recer结束后将所有计数加和。这种方法适用于只有有限个分类,而且拥有相同F值的记录不是很多的情况。例如网络日志处理和用户分类,用户的总数很多,但是每个用户的事件是有限的,以此分类得到的类别也是有限的。值得一提的是在这种模式下可以在数据传输到Recer之前使用Combiner来去除分类的重复值。

1 class Mapper
2 method Map(null, record [value f, categories [g1, g2,...] )
3 for all category g in [g1, g2,...]
4 Emit(value f, category g)
5
6 class Recer
7 method Initialize
8 H = new AssociativeArray : category -> count
9 method Rece(value f, categories [g1, g2,...])
10 [g1', g2',..] = ExcludeDuplicates( [g1, g2,..] )
11 for all category g in [g1', g2',...]
12 H{g} = H{g} + 1
13 method Close
14 for all category g in H do
15 Emit(category g, count H{g})

应用:日志分析,用户计数
互相关
问题陈述:有多个各由若干项构成的组,计算项两两共同出现于一个组中的次数。假如项数是N,那么应该计算N*N。
这种情况常见于文本分析(条目是单词而元组是句子),市场分析(购买了此物的客户还可能购买什么)。如果N*N小到可以容纳于一台机器的内存,实现起来就比较简单了。
配对法
第一种方法是在Mapper中给所有条目配对,然后在Recer中将同一条目对的计数加和。但这种做法也有缺点:
使用 combiners 带来的的好处有限,因为很可能所有项对都是唯一的
不能有效利用内存

1 class Mapper
2 method Map(null, items [i1, i2,...] )
3 for all item i in [i1, i2,...]
4 for all item j in [i1, i2,...]
5 Emit(pair [i j], count 1)
6
7 class Recer
8 method Rece(pair [i j], counts [c1, c2,...])
9 s = sum([c1, c2,...])
10 Emit(pair[i j], count s)

Stripes Approach(条方法?不知道这个名字怎么理解)
第二种方法是将数据按照pair中的第一项来分组,并维护一个关联数组,数组中存储的是所有关联项的计数。The second approach is to group data by the first item in pair and maintain an associative array (“stripe”) where counters for all adjacent items are accumulated. Recer receives all stripes for leading item i, merges them, and emits the same result as in the Pairs approach.
中间结果的键数量相对较少,因此减少了排序消耗。
可以有效利用 combiners。
可在内存中执行,不过如果没有正确执行的话也会带来问题。
实现起来比较复杂。
一般来说, “stripes” 比 “pairs” 更快

1 class Mapper
2 method Map(null, items [i1, i2,...] )
3 for all item i in [i1, i2,...]
4 H = new AssociativeArray : item -> counter
5 for all item j in [i1, i2,...]
6 H{j} = H{j} + 1
7 Emit(item i, stripe H)
8
9 class Recer
10 method Rece(item i, stripes [H1, H2,...])
11 H = new AssociativeArray : item -> counter
12 H = merge-sum( [H1, H2,...] )
13 for all item j in H.keys()
14 Emit(pair [i j], H{j})

应用:文本分析,市场分析
参考资料:Lin J. Dyer C. Hirst G. Data Intensive Processing MapRece
用MapRece 表达关系模式
在这部分我们会讨论一下怎么使用MapRece来进行主要的关系操作。
筛选(Selection)

1 class Mapper
2 method Map(rowkey key, tuple t)
3 if t satisfies the predicate
4 Emit(tuple t, null)

投影(Projection)
投影只比筛选稍微复杂一点,在这种情况下我们可以用Recer来消除可能的重复值。

1 class Mapper
2 method Map(rowkey key, tuple t)
3 tuple g = project(t) // extract required fields to tuple g
4 Emit(tuple g, null)
5
6 class Recer

D. java抽奖的算法

那你可以再1-10000之间随即嘛,概率小的奖品设置为1-10,概率大的设置为11-1000,最后随即出来的数判断一下在那个区间就可以了.
实体类,就是写一个JAVA BEAN嘛,里面记载奖品名字和数量啊,不懂可以追问

E. 有哪些经典的抽奖算法

常见的有两种

第一类是常见的有等级的抽奖活动,如一等、二等、三等奖等等

//分别为一、二、三、四等将的奖品数量,最后一个为未中奖的数量。
privatestaticfinalInteger[]lotteryList={5,10,20,40,100};

privateintgetSum(){
intsum=0;
for(intv:lotteryList){
sum+=v;
}
returnsum;
}

privateintgetLotteryLevel(){
Randomrandom=newRandom(System.nanoTime());
intsum=getSum();
for(inti=0;i<lotteryList.length;++i){
intrandNum=Math.abs(random.nextInt())%sum;
if(randNum<=lotteryList[i]){
returni;
}else{
sum-=lotteryList[i];
}
}
return-1;
}

第二类是不分等级的抽奖活动,仅需要参与人数与奖品总数,各奖品中奖概率相等。

//另一种抽奖算法,用于公司抽奖,即总参与人数与奖品数固定。
=75;
privatestaticfinalinttotal=175;
privatestaticSet<Integer>lotterySet=newHashSet<Integer>();
static{
for(inti=1;i<=lotteryNum;++i){
lotterySet.add(total*i/lotteryNum);
}
}
privateintgetLotteryNum2(){
Randomrand=newRandom(System.nanoTime());
intrandNum=Math.abs(rand.nextInt())%total;
if(lotterySet.contains(randNum)){
returnrandNum*lotteryNum/total;
}
return-1;
}

F. 如果从五个队中抽取两个有怎样的简便算法有多少种抽法

6个数任选3个(有序列排),6*5*46个数任选3个(无序列),因为c、b、a有3个数中排列有6种,abc acb bac cab bca cba 所以6个数任选3个(无序列)有6*5*4/6=20种

G. 搜索算法的应用案例

(1)题目:黑白棋游戏
黑白棋游戏的棋盘由4×4方格阵列构成。棋盘的每一方格中放有1枚棋子,共有8枚白棋子和8枚黑棋子。这16枚棋子的每一种放置方案都构成一个游戏状态。在棋盘上拥有1条公共边的2个方格称为相邻方格。一个方格最多可有4个相邻方格。在玩黑白棋游戏时,每一步可将任何2个相邻方格中棋子互换位置。对于给定的初始游戏状态和目标游戏状态,编程计算从初始游戏状态变化到目标游戏状态的最短着棋序列。
(2)分析
这题我们可以想到用深度优先搜索来做,但是如果下一步出现了以前的状态怎么办?直接判断时间复杂度的可能会有点大,这题的最优解法是用广度优先搜索来做。我们就可以有初始状态按照广度优先搜索遍历来扩展每一个点,这样到达目标状态的步数一定是最优的(步数的增加时单调的)。但问题是如果出现了重复的情况我们就必须要判重,但是朴素的判重是可以达到状态数级别的,其实我们可以考虑用hash表来判重。
Hash表:思路是根据关键码值进行直接访问。也就是说把一个关键码值映射到表中的一个位置来访问记录的过程。在Hash表中,一般插入,查找的时间复杂度可以在O(1)的时间复杂度内搞定。对于这一题我们可以用二进制值表示其hash值,最多2^16次方,所以我们开个2^16次方的表记录这个状态出现没有,这样可以在O(1)的时间复杂度内解决判重问题。
进一步考虑:从初始状态到目标状态,必定会产生很多无用的状态,那还有什么优化可以减少这时间复杂度?我们可以考虑把初始状态和目标状态一起扩展,这样如果初始状态的某个被扩展的点与目标状态所扩展的点相同时,那这两个点不用扩展下去,而两个扩展的步数和也就是答案。
上面的想法是双向广度优先搜索:
就像图二一样,多扩展了很多不必要的状态。
从上面一题可以看到我们用到了两种优化方法,即Hash表优化和双向广搜优化。一般的广度优先搜索用这两个优化就足以解决。

热点内容
荣耀50参数配置什么系统 发布:2025-08-13 23:45:26 浏览:242
有关卖软件的脚本 发布:2025-08-13 23:44:30 浏览:621
辉煌标准版服务器地址 发布:2025-08-13 23:35:14 浏览:252
安卓更新后更新包哪里去了 发布:2025-08-13 23:35:09 浏览:821
R2脚本下载 发布:2025-08-13 23:20:46 浏览:628
泰国云服务器访问人数 发布:2025-08-13 23:20:45 浏览:479
c语言太难 发布:2025-08-13 23:15:46 浏览:786
源代码编译后为什么会缩小 发布:2025-08-13 23:14:46 浏览:394
存储过程登录 发布:2025-08-13 23:03:12 浏览:497
刀工解压 发布:2025-08-13 22:45:20 浏览:516