a算法优化
⑴ A*算法应用,大家给点介绍,做课程设计
维基网络有很多的,大陆访问不了,可以设置个香港代理。
SHA 家族
[编辑首段]维基网络,自由的网络全书
跳转到: 导航, 搜寻
安全散列演算法能计算出一个数位讯息所对应到的,长度固定的字串(又称讯息摘要)。且若输入的讯息不同,它们对应到不同字串的机率很高;而 SHA 是FIPS所认证的五种安全杂凑演算法。这些演算法之所以称作“安全”是基于以下两点(根据官方标准的描述):“1)由讯息摘要反推原输入讯息,从计算理论上来说是很困难的。2)想要找到两组不同的讯息对应到相同的讯息摘要,从计算理论上来说也是很困难的。任何对输入讯息的变动,都有很高的机率导致其产生的讯息摘要迥异。”
SHA 家族的五个演算法,分别是SHA-1, SHA-224, SHA-256, SHA-384, 和 SHA-512,由美国国家安全局 (NSA) 所设计,并由美国国家标准与技术研究院(NIST) 发布;是美国的政府标准。后四者有时并称为SHA-2。SHA-1 在许多安全协定中广为使用,包括 TLS 和 SSL、 PGP、SSH、S/MIME 和 IPsec,曾被视为是 MD5(更早之前被广为使用的杂凑函数)的后继者。但 SHA-1 的安全性如今被密码学家严重质疑;虽然至今尚未出现对 SHA-2 有效的攻击,它的演算法跟 SHA-1 基本上仍然相似;因此有些人开始发展其他替代的杂凑演算法。缘于最近对 SHA-1 的种种攻击发表,“美国国家标准与技术研究院(NIST)开始设法经由公开竞争管道(类似高级加密标准AES的发展经过),发展一个或多个新的杂凑演算法。”
目录 [隐藏]
1 SHA-0 和 SHA-1
1.1 SHA-0 的破解
1.2 SHA-1 的破解
2 SHA-2
3 SHA 所定义的长度
4 SHAd
5 应用
6 SHA-1 演算法
7 SHA-2 演算法
8 参见
9 参考资料
10 外部链结
[编辑] SHA-0 和 SHA-1
SHA-1 压缩演算法中的一个回圈。A, B, C, D 和 E 是这个state中的 32 位元文字;F 是会变化的非线性函数;<<<n 代表bit向左循环移动n个位置。n因操作而异。田代表molo 232之下的加法,Kt 是一个常数。最初载明的演算法于 1993年发布,称做安全杂凑标准 (Secure Hash Standard),FIPS PUB 180。这个版本现在常被称为 SHA-0。它在发布之后很快就被 NSA 撤回,并且由 1995年发布的修订版本 FIPS PUB 180-1 (通常称为 SHA-1) 取代。SHA-1 和 SHA-0 的演算法只在压缩函数的讯息转换部份差了一个位元的循环位移。根据 NSA 的说法,它修正了一个在原始演算法中会降低密码安全性的错误。然而 NSA 并没有提供任何进一步的解释或证明该错误已被修正。而后 SHA-0 和 SHA-1 的弱点相继被攻破,SHA-1 似乎是显得比 SHA-0 有抵抗性,这多少证实了 NSA 当初修正演算法以增进安全性的声明。
SHA-0 和 SHA-1 可将一个最大 264 位元的讯息,转换成一串 160 位元的讯息摘要;其设计原理相似于 MIT 教授 Ronald L. Rivest 所设计的密码学杂凑演算法 MD4 和 MD5。
[编辑] SHA-0 的破解
在 CRYPTO 98 上,两位法国研究者提出一种对 SHA-0 的攻击方式 (Chabaud and Joux, 1998): 在 261的计算复杂度之内,就可以发现一次碰撞(即两个不同的讯息对应到相同的讯息摘要);这个数字小于 280 ,也就是说,其安全性不到一个理想的杂凑函数抵抗攻击所应具备的计算复杂度。
2004年时,Biham 和 Chen 也发现了 SHA-0 的近似碰撞 — 两个讯息可以杂凑出几乎相同的数值;其中 162 位元中有 142 位元相同。他们也发现了 SHA-0 的完整碰撞(相对于近似碰撞),将本来需要 80 次方的复杂度降低到 62 次方。
2004年8月12日,Joux, Carribault, Lemuet 和 Jalby 宣布找到 SHA-0 演算法的完整碰撞的方法,这是归纳 Chabaud 和 Joux 的攻击所完成的结果。发现一个完整碰撞只需要 251的计算复杂度。他们使用的是一台有 256 颗 Itanium2 处理器的超级电脑,约耗 80,000 CPU 工时 [1]。
2004年8月17日,在 CRYPTO 2004 的 Rump 会议上,王小云, 冯登国 (Feng), 来学嘉 (Lai), 和于红波 (Yu) 宣布了攻击 MD5、SHA-0 和其他杂凑函数的初步结果。他们攻击 SHA-0 的计算复杂度是 240,这意谓的他们的攻击成果比 Joux 还有其他人所做的更好。请参见 MD5 安全性。2005 年二月,王小云和殷益群、于红波再度发表了对 SHA-0 破密的演算法,可在 239 的计算复杂度内就找到碰撞。
[编辑] SHA-1 的破解
鉴于 SHA-0 的破密成果,专家们建议那些计画利用 SHA-1 实作密码系统的人们也应重新考虑。2004 年 CRYPTO 会议结果公布之后,NIST 即宣布他们将逐渐减少使用 SHA-1,改以 SHA-2 取而代之。
2005年,Rijmen 和 Oswald 发表了对 SHA-1 较弱版本(53次的加密回圈而非80次)的攻击:在 280 的计算复杂度之内找到碰撞。
2005年二月,王小云、殷益群及于红波发表了对完整版 SHA-1 的攻击,只需少于 269 的计算复杂度,就能找到一组碰撞。(利用暴力搜寻法找到碰撞需要 280 的计算复杂度。)
这篇论文的作者们写道;“我们的破密分析是以对付 SHA-0 的差分攻击、近似碰撞、多区块碰撞技术、以及从 MD5 演算法中寻找碰撞的讯息更改技术为基础。没有这些强力的分析工具,SHA-1 就无法破解。”此外,作者还展示了一次对 58 次加密回圈 SHA-1 的破密,在 233 个单位操作内就找到一组碰撞。完整攻击方法的论文发表在 2005 年八月的 CRYPTO 会议中。
殷益群在一次面谈中如此陈述:“大致上来说,我们找到了两个弱点:其一是前置处理不够复杂;其二是前 20 个回圈中的某些数学运算会造成不可预期的安全性问题。”
2005 年八月 17 的 CRYPTO 会议尾声中王小云、姚期智、姚储枫再度发表更有效率的 SHA-1 攻击法,能在 263 个计算复杂度内找到碰撞。
在密码学的学术理论中,任何攻击方式,其计算复杂度若少于暴力搜寻法所需要的计算复杂度,就能被视为针对该密码系统的一种破密法;这并不表示该破密法已经可以进入实际应用的阶段。
就应用层面的考量而言,一种新的破密法出现,暗示着将来可能会出现更有效率、足以实用的改良版本。虽然这些实用的破密法版本根本还没诞生,但确有必要发展更强的杂凑演算法来取代旧的演算法。在“碰撞”攻击法之外,另有一种反译攻击法,就是由杂凑出的字串反推原本的讯息;反译攻击的严重性更在碰撞攻击之上。 在许多会应用到密码杂凑的情境(如用户密码的存放、文件的数位签章等)中,碰撞攻击的影响并不是很大。举例来说,一个攻击者可能不会只想要伪造一份一模一样的文件,而会想改造原来的文件,再附上合法的签章,来愚弄持有私密金钥的验证者。另一方面,如果可以从密文中反推未加密前的使用者密码,攻击者就能利用得到的密码登入其他使用者的帐户,而这种事在密码系统中是不能被允许的。但若存在反译攻击,只要能得到指定使用者密码杂凑过后的字串(通常存在影档中,而且可能不会透露原密码资讯),就有可能得到该使用者的密码。
2006 年的 CRYPTO 会议上,Christian Rechberger 和 Christophe De Cannière 宣布他们能在容许攻击者决定部分原讯息的条件之下,找到 SHA-1 的一个碰撞。
[编辑] SHA-2
SHA-2 的第t个加密回圈。图中的深蓝色方块是事先定义好的非线性函数。ABCDEFGH一开始分别是八个初始值,Kt是第t个金钥,Wt是本区块产生第t个word。原讯息被切成固定长度的区块,对每一个区块,产生n个word(n视演算法而定),透过重复运作回圈n次对ABCDEFGH这八个工作区段循环加密。最后一次回圈所产生的八段字串合起来即是此区块对应到的杂凑字串。若原讯息包含数个区块,则最后还要将这些区块产生的杂凑字串加以混合才能产生最后的杂凑字串。NIST 发布了三个额外的 SHA 变体,这三个函数都将讯息对应到更长的讯息摘要。以它们的摘要长度 (以位元计算) 加在原名后面来命名:SHA-256,SHA-384 和 SHA-512。它们发布于 2001年的 FIPS PUB 180-2 草稿中,随即通过审查和评论。包含 SHA-1 的 FIPS PUB 180-2,于 2002年以官方标准发布。2004年2月,发布了一次 FIPS PUB 180-2 的变更通知,加入了一个额外的变种 "SHA-224",这是为了符合双金钥 3DES 所需的金钥长度而定义。
SHA-256 和 SHA-512 是很新的杂凑函数,前者以定义一个word为32位元,后者则定义一个word为64位元。它们分别使用了不同的偏移量,或用不同的常数,然而,实际上二者结构是相同的,只在回圈执行的次数上有所差异。 SHA-224 以及 SHA-384 则是前述二种杂凑函数的截短版,利用不同的初始值做计算。
这些新的杂凑函数并没有接受像 SHA-1 一样的公众密码社群做详细的检验,所以它们的密码安全性还不被大家广泛的信任。Gilbert 和 Handschuh (2003) 曾对这些新变种作过一些研究,声称他们没有弱点。
[编辑] SHA 所定义的长度
下表中的中继杂凑值(internal state)表示对每个资料区块压缩杂凑过后的中继值(internal hash sum)。详情请参见Merkle-Damgård construction。
演算法 输出杂凑值长度 (bits) 中继杂凑值长度 (bits) 资料区块长度 (bits) 最大输入讯息长度 (bits) 一个Word长度 (bits) 回圈次数 使用到的运运算元 碰撞攻击
SHA-0 160 160 512 264 − 1 32 80 +,and,or,xor,rotl 是
SHA-1 160 160 512 264 − 1 32 80 +,and,or,xor,rotl 存在263 的攻击
SHA-256/224 256/224 256 512 264 − 1 32 64 +,and,or,xor,shr,rotr 尚未出现
SHA-512/384 512/384 512 1024 2128 − 1 64 80 +,and,or,xor,shr,rotr 尚未出现
[编辑] SHAd
SHAd 函数是一个简单的相同 SHA 函数的重述:
SHAd-256(m)=SHA-256(SHA-256(m))。它会克服有关延伸长度攻击的问题。
[编辑] 应用
SHA-1, SHA-224, SHA-256, SHA-384 和 SHA-512 都被需要安全杂凑演算法的美国联邦政府所应用,他们也使用其他的密码演算法和协定来保护敏感的未保密资料。FIPS PUB 180-1 也鼓励私人或商业组织使用 SHA-1 加密。Fritz-chip 将很可能使用 SHA-1 杂凑函数来实现个人电脑上的数位版权管理。
首先推动安全杂凑演算法出版的是已合并的数位签章标准。
SHA 杂凑函数已被做为 SHACAL 分组密码演算法的基础。
[编辑] SHA-1 演算法
以下是 SHA-1 演算法的虚拟码:
Note: All variables are unsigned 32 bits and wrap molo 232 when calculating
Initialize variables:
h0 := 0x67452301
h1 := 0xEFCDAB89
h2 := 0x98BADCFE
h3 := 0x10325476
h4 := 0xC3D2E1F0
Pre-processing:
append the bit '1' to the message
append k bits '0', where k is the minimum number >= 0 such that the resulting message
length (in bits) is congruent to 448 (mod 512)
append length of message (before pre-processing), in bits, as 64-bit big-endian integer
Process the message in successive 512-bit chunks:
break message into 512-bit chunks
for each chunk
break chunk into sixteen 32-bit big-endian words w[i], 0 ≤ i ≤ 15
Extend the sixteen 32-bit words into eighty 32-bit words:
for i from 16 to 79
w[i] := (w[i-3] xor w[i-8] xor w[i-14] xor w[i-16]) leftrotate 1
Initialize hash value for this chunk:
a := h0
b := h1
c := h2
d := h3
e := h4
Main loop:
for i from 0 to 79
if 0 ≤ i ≤ 19 then
f := (b and c) or ((not b) and d)
k := 0x5A827999
else if 20 ≤ i ≤ 39
f := b xor c xor d
k := 0x6ED9EBA1
else if 40 ≤ i ≤ 59
f := (b and c) or (b and d) or (c and d)
k := 0x8F1BBCDC
else if 60 ≤ i ≤ 79
f := b xor c xor d
k := 0xCA62C1D6
temp := (a leftrotate 5) + f + e + k + w[i]
e := d
d := c
c := b leftrotate 30
b := a
a := temp
Add this chunk's hash to result so far:
h0 := h0 + a
h1 := h1 + b
h2 := h2 + c
h3 := h3 + d
h4 := h4 + e
Proce the final hash value (big-endian):
digest = hash = h0 append h1 append h2 append h3 append h4
上述关于 f 运算式列于 FIPS PUB 180-1 中 , 以下替代运算式也许也能在主要回圈里计算 f :
(0 ≤ i ≤ 19): f := d xor (b and (c xor d)) (alternative)
(40 ≤ i ≤ 59): f := (b and c) or (d and (b or c)) (alternative 1)
(40 ≤ i ≤ 59): f := (b and c) or (d and (b xor c)) (alternative 2)
(40 ≤ i ≤ 59): f := (b and c) + (d and (b xor c)) (alternative 3)
[编辑] SHA-2 演算法
以下是SHA-256 演算法的虚拟码。注意,64个word w[16..63]中的位元比起 SHA-1 演算法,混合的程度大幅提升。
Note: All variables are unsigned 32 bits and wrap molo 232 when calculating
Initialize variables
(first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19
Initialize table of round constants
(first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):
k[0..63] :=
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
Pre-processing:
append the bit '1' to the message
append k bits '0', where k is the minimum number >= 0 such that the resulting message
length (in bits) is congruent to 448 (mod 512)
append length of message (before pre-processing), in bits, as 64-bit big-endian integer
Process the message in successive 512-bit chunks:
break message into 512-bit chunks
for each chunk
break chunk into sixteen 32-bit big-endian words w[0..15]
Extend the sixteen 32-bit words into sixty-four 32-bit words:
for i from 16 to 63
s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
w[i] := w[i-16] + s0 + w[i-7] + s1
Initialize hash value for this chunk:
a := h0
b := h1
c := h2
d := h3
e := h4
f := h5
g := h6
h := h7
Main loop:
for i from 0 to 63
s0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
maj := (a and b) xor (a and c) xor (b and c)
t2 := s0 + maj
s1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
ch := (e and f) xor ((not e) and g)
t1 := h + s1 + ch + k[i] + w[i]
h := g
g := f
f := e
e := d + t1
d := c
c := b
b := a
a := t1 + t2
Add this chunk's hash to result so far:
h0 := h0 + a
h1 := h1 + b
h2 := h2 + c
h3 := h3 + d
h4 := h4 + e
h5 := h5 + f
h6 := h6 + g
h7 := h7 + h
Proce the final hash value (big-endian):
digest = hash = h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7
其中 ch 函数及 maj 函数可利用前述 SHA-1 的优化方式改写。
SHA-224 和 SHA-256 基本上是相同的, 除了:
h0 到 h7 的初始值不同,以及
SHA-224 输出时截掉 h7 的函数值。
SHA-512 和 SHA-256 的结构相同,但:
SHA-512 所有的数字都是64位元,
SHA-512 执行80次加密回圈而非64次,
SHA-512 初始值和常数拉长成64位元,以及
二者位元的偏移量和循环位移量不同。
SHA-384 和 SHA-512 基本上是相同的,除了:
h0 到 h7 的初始值不同,以及
SHA-384 输出时截掉 h6 和 h7 的函数值。
⑵ 最短路问题,会Dijkstra 算法和A*算法的进来,C/C++实现~追加高分哦!
A*算法不能同时求所有点,要有目标,比如选A8为目标。需要有一个估价函数h()来估计一个点到达目标点的代价下界,比如这里你可以选择与一个点相连的最小的边权值(这不精确,你可以自己设计h(),h()值越大越好,但不能大于一个点到目标的实际最小值)。另外每个点还有一个值f(),就相当于Dijkstra中的已经算出的的起点到达该点的花费。
然后A*算法中每次找f()+h()值最小的点进行扩展,可以证明这样的算法找到目标扩展的节点总数少于Dijkstra
极限情况下,如果h()函数设计的很差,每次都为0,你的算法就每次都找f()值最小的点进行扩展,就退化为Dijkstra,如果h()函数的值大一点,越大效率越高(当然不能大于实际值)。
你的图节点数太少了,多搞几个节点才能数出来,A*扩展的节点更少
⑶ 求A,B间素数的优化算法
我提供一种“伪素数”算法。
先用筛法筛出31622之内的素数,再判断A,B间各数能不能被31622之内的素数整除。在一定范围内(其实这个范围也很大了)这种方法是完全正确的。
参考程序:oibh7月基础版普及组月赛“天天写作业”的标程。
var
prime : array[1..3401] of integer;
n : integer;
a, b : longint;
sum : longint;
procere pre_work;
const
num = 31622;
var
hash : array[1..num] of boolean;
i ,j : integer;
begin
fillchar(hash, sizeof(hash), true);
hash[1] := false;
for i := 2 to trunc(sqrt(num)) do
begin
if not hash[i] then continue;
j := i + i;
while j <= num do
begin
hash[j] := false;
inc(j, i);
end;
end;
for i := 2 to num do
if hash[i] then
begin
inc(n);
prime[n] := i;
end;
end;
procere init;
begin
assign(input, 'homework.in');
reset(input);
assign(output, 'homework.out');
rewrite(output);
readln(a, b);
close(input);
end;
function judge(p: longint): boolean;
var
t, i : longint;
begin
t := trunc(sqrt(p));
for i := 1 to n do
if prime[i] > t then break
else if p mod prime[i] = 0 then
begin
judge := false;
exit;
end;
judge := true;
end;
procere work;
var
i : longint;
begin
if a = 1 then a := 2;
for i := a to b do
if judge(i) then
inc(sum);
end;
procere outit;
begin
writeln(sum);
close(output);
end;
begin
pre_work;
init;
work;
outit;
end.
⑷ 为什么a*算法会出现重复扩展节点的问题解决的方法有哪些
算法没有错。只是考虑到所有可能的情况。
如果x出现在close集中,并且新的估价小于原有估价,说明还存在另一条经过x到达目标并且更快捷路径是之前没有搜索到的。这时当然要重新把x放回open集中统一考虑。
依你所讲,大概你是在方格棋盘类的路径搜索。则上述情况不会出现,因为方格棋盘构造出的图很规则。但如果是在某一非常奇怪的图上,比如两行星之间有个虫洞,经过后可以使时间倒流时(哈哈,暂时只想到这样一个奇怪的例子),则很有可能出现上述情况。
所以,不是算法谁对谁错,而是在不同问题中做法不一样。网络给出的算法考虑情况更全面。
⑸ 广度优先算法的优化——A*算法问题
英文叫 a-star 中文叫a星
我以前见过用astar算法求解这类问题的论文
你在上搜索一下 “A星算法”有这方面的解释
⑹ 使用A*算法解决路径优化问题 必须需要编写程序吗 如果需要编写的话使用什么软件呢
这是一种算法
使用各种编程语言都可以做的
你选择自己擅长的语言跟工具就行了
⑺ 如何利用矩阵对a*算法进行优化
如果A确实能完全存入一级缓存,那么把B按列分块,一块一块乘就行了.
一般来讲矩阵乘法并不是像你说的那样做的,而要把A,B,C都分块,对于每一级存贮器而言,应该至少分成5个部分来管理.比如说,A的某一块常驻于这一级存贮,然后余下的部分分为四块:
(1)上一步已经运算完成的C块——写入低一级存贮
(2)下一步将参与运算的B块——从低一级存贮读入
(3),(4)正在参与运算的B和C块
然后对于这一级存贮器上的小矩阵块运算C=AB仍然按照同样的管理方式递交给上一级存贮来计算.一般来讲A块选得略小一点,具体的分配方式取决于运算和I/O的速度,尽量保持计算单元忙碌.
⑻ A*算法如何改进
十万火急:此改进的模糊C-此函数实现遗传算法,用于模糊C-均值聚类 %% A=farm(:,Ser(1)); B=farm(:,Ser(2)); P0=unidrnd(M-1); a=[
⑼ A*算法用于路径规划,有什么缺点
缺点:A*算法通过比较当前路径栅格的8个邻居的启发式函数值F来逐步确定下一个路径栅格,当存在多个最小值时A*算法不能保证搜索的路径最优。
A*算法;A*(A-Star)算法是一种静态路网中求解最短路径最有效的直接搜索方法。估价值与实际值越接近,估价函数取得就越好。A*[1] (A-Star)算法是一种静态路网中求解最短路最有效的直接搜索方法。注意是最有效的直接搜索算法。之后涌现了很多预处理算法(ALT,CH,HL等等),在线查询效率是A*算法的数千甚至上万倍。公式表示为: f(n)=g(n)+h(n),其中 f(n) 是从初始点经由节点n到目标点的估价函数,g(n) 是在状态空间中从初始节点到n节点的实际代价,h(n) 是从n到目标节点最佳路径的估计代价。保证找到最短路径(最优解的)条件,关键在于估价函数f(n)的选取:估价值h(n)<= n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低。但能得到最优解。并且如果h(n)=d(n),即距离估计h(n)等于最短距离,那么搜索将严格沿着最短路径进行, 此时的搜索效率是最高的。如果 估价值>实际值,搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。
⑽ A*算法介绍
姓名:车文扬 学号:16020199006
【嵌牛导读】:A*算法的逐步详解
【嵌牛鼻子】:启发式算法
【嵌牛提问】:A*算法的原理是什么?
【嵌牛正文】:
A*算法
路径规划是指的是机器人的最优路径规划问题,即依据某个或某些优化准则(如工作代价最小、行走路径最短、行走时间最短等),在工作空间中找到一个从起始状态到目标状态能避开障碍物的最优路径。机器人的路径规划应用场景极丰富,最常见如游戏中NPC及控制角色的位置移动,网络地图等导航问题,小到家庭扫地机器人、无人机大到各公司正争相开拓的无人驾驶汽车等。
目前路径规划算法分为:
A*算法原理:
在计算机科学中,A*算法作为Dijkstra算法的扩展,因其高效性而被广泛应用于寻路及图的遍历,如星际争霸等游戏中就大量使用。在理解算法前,我们需要知道几个概念:
搜索区域(The Search Area):图中的搜索区域被划分为了简单的二维数组,数组每个元素对应一个小方格,当然我们也可以将区域等分成是五角星,矩形等,通常将一个单位的中心点称之为搜索区域节点(Node)。
开放列表(Open List):我们将路径规划过程中待检测的节点存放于Open List中,而已检测过的格子则存放于Close List中。
父节点(parent):在路径规划中用于回溯的节点,开发时可考虑为双向链表结构中的父结点指针。
路径排序(Path Sorting):具体往哪个节点移动由以下公式确定:F(n) = G + H 。G代表的是从初始位置A沿着已生成的路径到指定待检测格子的移动开销。H指定待测格子到目标节点B的估计移动开销。
启发函数(Heuristics Function):H为启发函数,也被认为是一种试探,由于在找到唯一路径前,我们不确定在前面会出现什么障碍物,因此用了一种计算H的算法,具体根据实际场景决定。在我们简化的模型中,H采用的是传统的曼哈顿距离(Manhattan Distance),也就是横纵向走的距离之和。
如下图所示,绿色方块为机器人起始位置A,红色方块为目标位置B,蓝色为障碍物。
我们把要搜寻的区域划分成了正方形的格子。这是寻路的第一步,简化搜索区域。这个特殊的方法把我们的搜索区域简化为了2 维数组。数组的每一项代表一个格子,它的状态就是可走(walkalbe)或不可走(unwalkable) 。现用A*算法寻找出一条自A到B的最短路径,每个方格的边长为10,即垂直水平方向移动开销为10。因此沿对角移动开销约等于14。具体步骤如下:
从起点 A 开始,把它加入到一个由方格组成的open list(开放列表) 中,这个open list像是一个购物清单。Open list里的格子是可能会是沿途经过的,也有可能不经过。因此可以将其看成一个待检查的列表。查看与A相邻的8个方格 ,把其中可走的 (walkable) 或可到达的(reachable) 方格加入到open list中。并把起点 A 设置为这些方格的父节点 (parent node) 。然后把 A 从open list中移除,加入到close list(封闭列表) 中,close list中的每个方格都是不需要再关注的。
如下图所示,深绿色的方格为起点A,它的外框是亮蓝色,表示该方格被加入到了close list 。与它相邻的黑色方格是需要被检查的,他们的外框是亮绿色。每个黑方格都有一个灰色的指针指向他们的父节点A。
下一步,我们需要从open list中选一个与起点A相邻的方格。但是到底选择哪个方格好呢?选F值最小的那个。我们看看下图中的一些方格。在标有字母的方格中G = 10 。这是因为水平方向从起点到那里只有一个方格的距离。与起点直接相邻的上方,下方,左方的方格的G 值都是10 ,对角线的方格G 值都是14 。H值通过估算起点到终点( 红色方格) 的Manhattan 距离得到,仅作横向和纵向移动,并且忽略沿途的障碍。使用这种方式,起点右边的方格到终点有3 个方格的距离,因此H = 30 。这个方格上方的方格到终点有4 个方格的距离( 注意只计算横向和纵向距离) ,因此H = 40 。
比较open list中节点的F值后,发现起点A右侧节点的F=40,值最小。选作当前处理节点,并将这个点从Open List删除,移到Close List中。
对这个节点周围的8个格子进行判断,若是不可通过(比如墙,水,或是其他非法地形)或已经在Close List中,则忽略。否则执行以下步骤:
若当前处理节点的相邻格子已经在Open List中,则检查这条路径是否更优,即计算经由当前处理节点到达那个方格是否具有更小的 G值。如果没有,不做任何操作。相反,如果G值更小,则把那个方格的父节点设为当前处理节点 ( 我们选中的方格 ) ,然后重新计算那个方格的 F 值和 G 值。
若当前处理节点的相邻格子不在Open List中,那么把它加入,并将它的父节点设置为该节点。
按照上述规则我们继续搜索,选择起点右边的方格作为当前处理节点。它的外框用蓝线打亮,被放入了close list 中。然后我们检查与它相邻的方格。它右侧的3个方格是墙壁,我们忽略。它左边的方格是起点,在close list 中,我们也忽略。其他4个相邻的方格均在open list 中,我们需要检查经由当前节点到达那里的路径是否更好。我们看看上面的方格,它现在的G值为14 ,如果经由当前方格到达那里,G值将会为20( 其中10为从起点到达当前方格的G值,此外还要加上从当前方格纵向移动到上面方格的G值10) ,因此这不是最优的路径。看图就会明白直接从起点沿对角线移动到那个方格比先横向移动再纵向移动要好。
当把4个已经在open list 中的相邻方格都检查后,没有发现经由当前节点的更好路径,因此不做任何改变。接下来要选择下一个待处理的节点。因此再次遍历open list ,现在open list中只有7 个方格了,我们需要选择F值最小的那个。这次有两个方格的F值都是54,选哪个呢?没什么关系。从速度上考虑,选择最后加入open list 的方格更快。因此选择起点右下方的方格,如下图所示。
接下来把起点右下角F值为54的方格作为当前处理节点,检查其相邻的方格。我们发现它右边是墙(墙下面的一格也忽略掉,假定墙角不能直接穿越),忽略之。这样还剩下 5 个相邻的方格。当前方格下面的 2 个方格还没有加入 open list ,所以把它们加入,同时把当前方格设为他们的父亲。在剩下的 3 个方格中,有 2 个已经在 close list 中 ( 一个是起点,一个是当前方格上面的方格,外框被加亮的 ) ,我们忽略它们。最后一个方格,也就是当前方格左边的方格,检查经由当前方格到达那里是否具有更小的 G 值。没有,因此我们准备从 open list 中选择下一个待处理的方格。
不断重复这个过程,直到把终点也加入到了open list 中,此时如下图所示。注意在起点下方2 格处的方格的父亲已经与前面不同了。之前它的G值是28并且指向它右上方的方格。现在它的G 值为20 ,并且指向它正上方的方格。这是由于在寻路过程中的某处使用新路径时G值更小,因此父节点被重新设置,G和F值被重新计算。
那么我们怎样得到实际路径呢?很简单,如下图所示,从终点开始,沿着箭头向父节点移动,直至回到起点,这就是你的路径。
A*算法总结:
1. 把起点加入 open list 。
2. 重复如下过程:
a. 遍历open list ,查找F值最小的节点,把它作为当前要处理的节点,然后移到close list中
b. 对当前方格的 8 个相邻方格一一进行检查,如果它是不可抵达的或者它在close list中,忽略它。否则,做如下操作:
□ 如果它不在open list中,把它加入open list,并且把当前方格设置为它的父亲
□ 如果它已经在open list中,检查这条路径 ( 即经由当前方格到达它那里 ) 是否更近。如果更近,把它的父亲设置为当前方格,并重新计算它的G和F值。如果你的open list是按F值排序的话,改变后你可能需要重新排序。
c. 遇到下面情况停止搜索:
□ 把终点加入到了 open list 中,此时路径已经找到了,或者
□ 查找终点失败,并且open list 是空的,此时没有路径。
3. 从终点开始,每个方格沿着父节点移动直至起点,形成路径。