请教几个算法,分不够可以加~~

dengsf 2003-11-23 09:11:26
加精
以下的算法,希望大家“不”要给出具体的程序实现,而是尽量用比较“简洁”的语言来表达出算法本身的“思想或做法”。给出链接也可以。
------------------------------------------------------------

首先是中缀表达式的求值,我觉得要用编译原理的思想去做——都是列出可能的符号的优先级,然后用栈操作。可是看大家平时的讨论,好象有一种专门的比较简洁的方法可以处理(就像处理后缀一样)。请指教。
------------------------------------------------------------

其次是A*算法。我老是听到大家谈起,我知道这应该是个路径寻找的方法。请问具体的思想和实现。
------------------------------------------------------------

还有是 模拟退火 和 遗传 算法。本人很菜,根本不知道这些用在什么地方,抱着想了解一下的心情去学习。大家有什么好的入门文章请推荐,亲自指教更好。
...全文
75 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
dengsf 2003-12-02
  • 打赏
  • 举报
回复
多谢各为老大支持,结帖了~~
LeeMaRS 2003-12-01
  • 打赏
  • 举报
回复
中缀就是一般的算式, 当然要确定优先级了
前缀和后缀都不要.
saint001 2003-12-01
  • 打赏
  • 举报
回复
数据结构学的不好
给一个中缀表达式计算好像不要确定符号的优先级
前缀表达式、后缀表达式计算都不要吧
优先级已经包含在其中了



概率算法求的是近似解,往往想得到最优解但求最优解复杂度太大,实际中能够得到满足一定要求的近似解往往就可以了
dengsf 2003-12-01
  • 打赏
  • 举报
回复
最后一顶~~~~~~~
donghid 2003-11-29
  • 打赏
  • 举报
回复
关注一下
dengsf 2003-11-28
  • 打赏
  • 举报
回复
恩,有个大概的了解了。多谢saint001。

上面介绍的两个算法,都说是以“概率”方式产生下一个状态或下一个组合……是否这些算法就通常用在启发式的,求出近似解而不是最优解的场合中?


还有那个“中缀表达式”,老是听各位老大说简单。
请问如果你们要实现一个判定中缀表达式的程序,是否要预先“确定符号的优先级”?是否都说一声好吗?
saint001 2003-11-26
  • 打赏
  • 举报
回复
遗传算法
遗传算法以生物进化过程为背景,模拟生物进化的步骤,将繁殖、杂交、变异、竞争和选择等概念引入到算法中,通过维持一组可行解,并通过对可行解的重新组合,改进可行解在多维空间内的移动轨迹或趋向,最终走向最优解。它克服了传统优化方法容易陷入局部极值的缺点,是一种全局优化算法。遗传算法的步骤如下:
(1)定义一个目标函数;

(2)将可行解群体在一定的约束条件下初始化,每一个可行解用一个向量x来编码,称为一条染色体,向量的分量代表基因,它对应可行解的某一决策变量;

(3)计算群体中每条染色体xi(i=1,2,…,n)所对应的目标函数值,并以此计算适应值Fi,按Fi的大小来评价该可行解的好坏;
(4)以优胜劣汰的机制,将适应值差的染色体淘汰掉,对幸存的染色体根据其适应值的好坏,按概率随机选择,进行繁殖,形成新的群体;
(5)通过杂交和变异的操作,产生子代。杂交是随机选择两条染色体(双亲),将某一点或多点的基因互换而产生两个新个体,变异是基因中的某一点或多点发生突变;
(6)对子代群体重复步骤(3)~(5)的操作,进行新一轮遗传进化过程,直到迭代收敛(适应值趋稳定)即找到了最优解或准最优解。

http://chinaunix.net/jh/23/52955.html
saint001 2003-11-26
  • 打赏
  • 举报
回复
我来说说模拟退火,没有专门的分析过

模拟退火(simulated annealing)算法是局部搜索算法的扩展,它不同于局部搜索之处是以一定的概率选择邻域中目标值大的状态(假定目标要求最小)。理论上来说,它是一个全局最优算法。
退火是一种物理过程,一种金属物体在加热到一定的温度后,它的所有分子在状态空间D中自由运动。随着温度的下降,这些分子逐渐停留在不同的状态。在温度最低时,分子重新以一定的结构排列。统计力学研究表明,在温度t,分子停留在状态r的概率满足波兹曼(Boltzmann)概率分布
P(E=Er)=exp(-Er/kT)/Z(T)
.......
后面有好多分析和推导

最后的结论(方法)是
分子状态(搜索状态)由温度低的一个状态(目标值小)运动到温度值高的一个状态(目标值大)的概率是和当前温度有关的,温度越低,转化的概率越大。
温度参数是模拟退火的关键技术,温度决定着目标值增大的概率
有三个问题:
1)初始温度的选取;
2)温度的下降方法;
3)停止温度的确定;


说了这么多,其实算法思想就是
1)初始状态S,初始温度T
2)在S邻域内随机选取状态S1
如果f(S1)<f(S),接受S1(即S=S1)
否则,按照概率p接受S1,p是与T和f(S)-f(S1)相关的函数
如果没有达到停止条件(使T温度下的状态搜索完成,温度降低)
执行2)
否则
执行3)
3)T=新的T(降低温度),
如果满足停止条件,停止计算
否则,转2)

实现的过程中,要具体问题具体分析,完成细节
dengsf 2003-11-26
  • 打赏
  • 举报
回复
哦,原来这就是 A* 算法。多谢 bluesky2008!
这种思想以前好象也看过,原来就是大名鼎鼎的A*算法;而且A*准确来说是用了某种思想的一类算法,而不是某个具体的算法>_<。看来路径只是它的一个很简单的应用而已~~~


其它问题劳烦各位老大继续帮忙。
那个中缀表达式,大家不必给出具体的程序。我知道用类似编译的思想可以实现,但要确定 运算符、数字、括号 的优先级,请问是否有一种简便的方法可以实现——就类似求后缀一样,进进出出就行了……——只要说有和没就行了。

还有 模拟退火 和 遗传算法,看名字应该是某种数学模型(完全没接触过,惨!),请大家 介绍一下 “大概的思想”,不要求 太多细节 但 力求表述“准确和严密”,不要有某个晦涩的概念一下子带过这样子的。
aaalife 2003-11-26
  • 打赏
  • 举报
回复
BlueSky2008 2003-11-26
  • 打赏
  • 举报
回复
看看最重要的函数GenerateSucc:
void AstarPathfinder::GenerateSucc(NODE *BestNode,int x,int y,int dx,int dy)
{
int g, TileNumS, c = 0;
NODE *Old, *Successor;
//计算子节点的 g 值
g = BestNode->g+1; //g(Successor)=g(BestNode)+cost of getting
//from BestNode to Successor
TileNumS = TileNum(x,y); // identification purposes
//子节点再Open表中吗?
if ( (Old=CheckOPEN(TileNumS)) != NULL ) // if equal to NULL then
//not in OPEN list, else it returns the Node in Old
{
//若在
for( c = 0; c < 8; c++)
if( BestNode->Child[c] == NULL ) // Add Old to the list of
// BestNode's Children (or Successors).
break;
BestNode->Child[c] = Old;
//比较Open表中的估价值和当前的估价值(只要比较g值就可以了)
if ( g < Old->g ) // if our new g value is < Old's then
//reset Old's parent to point to BestNode
{
//当前的估价值小就更新Open表中的估价值
Old->Parent = BestNode;
Old->g = g;
Old->f = g + Old->h;
}
}
else //在Closed表中吗?
if ( (Old=CheckCLOSED(TileNumS)) != NULL ) // if equal to NULL then
// not in OPEN list, else it returns the Node in Old
{
//若在
for( c = 0; c< 8; c++)
if ( BestNode->Child[c] == NULL ) // Add Old to the list of
//BestNode's Children (or Successors).
break;
BestNode->Child[c] = Old;
//比较Closed表中的估价值和当前的估价值(只要比较g值就可以了)
if ( g < Old->g ) // if our new g value is < Old's then
// reset Old's parent to point to BestNode
{
//当前的估价值小就更新Closed表中的估价值
Old->Parent = BestNode;
Old->g = g;
Old->f = g + Old->h;
//再依次更新Old的所有子节点的估价值
PropagateDown(Old); // Since we changed the g value of
//Old,we need to propagate this new
//value downwards, i.e.
// do a Depth-First traversal of the tree!
}
}
else//不在Open表中也不在Close表中
{
//生成新的节点
Successor = ( NODE* )calloc(1,sizeof( NODE ));
Successor->Parent = BestNode;
Successor->g = g;
Successor->h = (x-dx)*(x-dx) + (y-dy)*(y-dy); // should do
// sqrt(), but since we don't really
Successor->f = g+Successor->h; // care about the distance but
//just which branch looks
Successor->x = x; // better this should suffice.
// Anyayz it's faster.
Successor->y = y;
Successor->NodeNum = TileNumS;
//再插入Open表中,同时排序。
Insert(Successor); // Insert Successor on OPEN list wrt f
for( c =0; c < 8; c++)
if ( BestNode->Child[c] == NULL ) // Add Old to the
// list of BestNode's Children (or Successors).
break;
BestNode->Child[c] = Successor;
}
}
BlueSky2008 2003-11-26
  • 打赏
  • 举报
回复
三、用A*算法实现最短路径的搜索
在游戏设计中,经常要涉及到最短路径的搜索,现在一个比较好的方法
就是用A*算法进行设 计。他的好处我们就不用管了,反正就是好!^_*
注意下面所说的都是以 ClassAstar 这个程序为蓝本,你可以在这里
下载这个程序。这个程 序是一个完整的工程。里面带了一个EXE文件。
可以先看看。
先复习一下,A*算法的核心是估价函数f(n),它包括g(n)和h(n)两部分.
g(n) 是已经走过的 代价,h(n)是n到目标的估计代价。在这个例子
中g(n)表示在状态空间从起始节点到 n节点的 深度,h(n)表示n节点
所在地图的位置到目标位置的直线距离。啊!一个是状态空间,一个
是 实际的地图,不要搞错了。再详细点说,有一个物体A,在地图上
的坐标是(xa,ya),A所要到 达的目标b的坐标是(xb,yb)。则开始搜索
时,设置一个起始节点1,生成八个子节点2 - 9 因 为有八个方向。
如图: 节 点 1 g(1)=0
/| | \ h(1)=(Xb*Xb-Xa*Xa)+(Yb*Yb-Ya*Ya)
/ / | \
/ / | \
节点2 节点3 节点4...节点9 g(9)=1
/|\ h(9)=(Xb*Xb-X9*X9)+(Yb*Yb-Y9*Y9)
/ | \
           /   |   \    
节点10 节点11...节点17 g(17)=2
h(17)=(Xb*Xb-X17*X17)+(Yb*Yb-Y17*Y17)
仔细看看节点1、9、17的g(n)和h(n)是怎么计算的。现在应该知道了
下面程序中的f(n)是如何 计算的吧。开始讲解源程序了。其实这个
序是一个很典型的教科书似的程序,也就是说只要 你看懂了上面的
伪程序,这个程序是十分容易理解的。不过他和上面的伪程序有一些
的不同, 我在后面会提出来。
先看搜索主函数:
void AstarPathfinder::FindPath(int sx, int sy, int dx, int dy)
{
NODE *Node, *BestNode;
int TileNumDest;
//得到目标位置,作判断用
TileNumDest = TileNum(sx, sy);
//生成Open和Closed表
OPEN=( NODE* )calloc(1,sizeof( NODE ));
CLOSED=( NODE* )calloc(1,sizeof( NODE ));
//生成起始节点,并放入Open表中
Node=( NODE* )calloc(1,sizeof( NODE ));
Node->g = 0;
//这是计算h值
Node->h = (dx-sx)*(dx-sx) + (dy-sy)*(dy-sy); //此处按道理应用开方
//这是计算f值,即估价值
Node->f = Node->g+Node->h;
Node->NodeNum = TileNum(dx, dy);
Node->x = dx;
Node->y = dy;

OPEN->NextNode=Node; // make Open List point to first node
for (;;)
{ //从Open表中取得一个估价值最好的节点
BestNode=ReturnBestNode();
//如果该节点是目标节点就退出
if (BestNode->NodeNum == TileNumDest) // if we've found the
//end, break and finish
break;
//否则生成子节点
GenerateSuccessors(BestNode,sx,sy);
}
PATH = BestNode;
}
再看看生成子节点函数 GenerateSuccessors:
void AstarPathfinder::GenerateSuccessors(NODE *BestNode,int dx,int dy)
{
int x, y;
//哦!依次生成八个方向的子节点,简单!
// Upper-Left
if ( FreeTile(x=BestNode->x-TILESIZE, y=BestNode->y-TILESIZE) )
GenerateSucc(BestNode,x,y,dx,dy);
// Upper
if ( FreeTile(x=BestNode->x, y=BestNode->y-TILESIZE) )
GenerateSucc(BestNode,x,y,dx,dy);
// Upper-Right
if ( FreeTile(x=BestNode->x+TILESIZE, y=BestNode->y-TILESIZE) )
GenerateSucc(BestNode,x,y,dx,dy);
// Right
if ( FreeTile(x=BestNode->x+TILESIZE, y=BestNode->y) )
GenerateSucc(BestNode,x,y,dx,dy);
// Lower-Right
if ( FreeTile(x=BestNode->x+TILESIZE, y=BestNode->y+TILESIZE) )
GenerateSucc(BestNode,x,y,dx,dy);
// Lower
if ( FreeTile(x=BestNode->x, y=BestNode->y+TILESIZE) )
GenerateSucc(BestNode,x,y,dx,dy);
// Lower-Left
if ( FreeTile(x=BestNode->x-TILESIZE, y=BestNode->y+TILESIZE) )
GenerateSucc(BestNode,x,y,dx,dy);
// Left
if ( FreeTile(x=BestNode->x-TILESIZE, y=BestNode->y) )
GenerateSucc(BestNode,x,y,dx,dy);
}
BlueSky2008 2003-11-26
  • 打赏
  • 举报
回复
发信人: sharkman (虾米), 信区: Algorithm
标 题: 深入A*算法
发信站: 武汉白云黄鹤站 (Sat Oct 14 23:48:07 2000), 站内信件

一、前言
在这里我将对A*算法的实际应用进行一定的探讨,并且举一个有关A*
算法在最短路径搜索 的例子。值得注意的是这里并不对A*的基本的概
念作介绍,如果你还对A*算法不清楚的话, 请看姊妹篇《初识A*算法》。
二、A*算法的程序编写原理
我在《初识A*算法》中说过,A*算法是最好优先算法的一种。只是有一
些约束条件而已。 我们先来看看最好优先算法是如何编写的吧。
如图有如下的状态空间:(起始位置是A,目标位置是P,字母后的数字表示节点的估价
值)
A - 5
/ │ \
                /  │  \
               ↓   ↓   \
               B-4  C-4     D-6
              /|  / \     /\  
             / |  /   \   /  \  
            /  |  |  ↓   |   \    
           E-5  F-5  G-4  H-3  I    J         
  
           /\   /\ |  / \  /\   \        
 
          /  \ /  ||  /  \ / \   \        
    
         /   v   || ↓   ↓/  \  \       
     
         K    L   M N  O-2  P-3   Q R       
     
         |  |                       
| |
| |
S T
搜索过程中设置两个表:OPEN和CLOSED。OPEN表保存了所有已生
成而未考察的节点,CLOSED 表中记录已访问过的节点。算法中有一步
是根据估价函数重排OPEN表。这样循环中的每一 步只考虑OPEN表中状
态最好的节点。具体搜索过程如下:

1)初始状态:
OPEN=[A5];CLOSED=[];
2)估算A5,取得搜有子节点,并放入OPEN表中;
OPEN=[B4,C4,D6];CLOSED=[A5]
3)估算B4,取得搜有子节点,并放入OPEN表中;
OPEN=[C4,E5,F5,D6];CLOSED=[B4,A5]
4)估算C4;取得搜有子节点,并放入OPEN表中;
OPEN=[H3,G4,E5,F5,D6];CLOSED=[C4,B4,A5]
5)估算H3,取得搜有子节点,并放入OPEN表中;
OPEN=[O2,P3,G4,E5,F5,D6];CLOSED=H3C4,B4,A5]
6)估算O2,取得搜有子节点,并放入OPEN表中;
OPEN=[P3,G4,E5,F5,D6];CLOSED=[O2,H3,C4,B4,A5]
7)估算P3,已得到解;
看了具体的过程,再看看伪程序吧。算法的伪程序如下:

Best_First_Search()
{
Open = [起始节点]; Closed = [];
while ( Open表非空 )
{
从Open中取得一个节点X,并从OPEN表中删除。
if (X是目标节点)
{
求得路径PATH;返回路径PATH;
}
for (每一个X的子节点Y)
{
if( Y不在OPEN表和CLOSE表中 )
{
求Y的估价值;并将Y插入OPEN表中;//还没有排序
}
else
if( Y在OPEN表中 )
{
if( Y的估价值小于OPEN表的估价值 )
更新OPEN表中的估价值;
}
else //Y在CLOSE表中
{
if( Y的估价值小于CLOSE表的估价值 )
{
更新CLOSE表中的估价值;
从CLOSE表中移出节点,并放入OPEN表中;
}
}
将X节点插入CLOSE表中;
按照估价值将OPEN表中的节点排序;
}//end for
}//end while
}//end func
啊!伪程序出来了,写一个源程序应该不是问题了,依葫芦画瓢就可以。
A*算法的程序与此 是一样的,只要注意估价函数中的g(n)的h(n)约束
条件就可以了。不清楚的可以看看《初识A*算法》。好了,我们可以
进入另一个重要的话题,用A*算法实现最短路径的搜索。在此之 前你
最好认真的理解前面的算法。
BlueSky2008 2003-11-26
  • 打赏
  • 举报
回复
转贴两篇:

初识A*算法

A*在游戏设计中有它很典型的用法,是人工智能在游戏中的代表。
A*算法在人工智能中是一种典型的启发式搜索算法,为了说清楚
A*算法,我看还是先说说何谓启发式算法。

一、何谓启发式搜索算法:
在说它之前先提提状态空间搜索。状态空间搜索,如果按专业点的说
法就是将问题求解过程表现为从 初始状态到目标状态寻找这个路径的
过程。通俗点说,就是在解一个问题时,找到一条解题的过程可以从
求解的开始到问题的结果(好象并不通俗哦)。由于求解问题的过程
中分枝有很多,主要是求解过程中求 解条件的不确定性,不完备性造
成的,使得求解的路径很多这就构成了一个图,我们说这个图就是状
态空 间。问题的求解实际上就是在这个图中找到一条路径可以从开始
到结果。这个寻找的过程就是状态空间搜索。
常用的状态空间搜索有深度优先和广度优先。广度优先是从初始状态
一层一层向下找,直到找到目标 为止。深度优先是按照一定的顺序前
查找完一个分支,再查找另一个分支,以至找到目标为止。这两种算
法在数据结构书中都有描述,可以参看这些书得到更详细的解释。
前面说的广度和深度优先搜索有一个很大的缺陷就是他们都是在一个
给定的状态空间中穷举。这在状 态空间不大的情况下是很合适的算法
,可是当状态空间十分大,且不预测的情况下就不可取了。他的效率
实在太低,甚至不可完成。在这里就要用到启发式搜索了。
启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,
得到最好的位置,再从这个位置 进行搜索直到目标。这样可以省略
大量无畏的搜索路径,提到了效率。在启发式搜索中,对位置的估价
是十分重要的。采用了不同的估价可以有不同的效果。我们先看看
估价是如何表示的。
启发中的估价是用估价函数表示的,如:
f(n) = g(n) + h(n)
其中f(n) 是节点n的估价函数,g(n)实在状态空间中从初始节点到
n节点的实际代价,h(n)是从n到目 标节点最佳路径的估计代价。在
这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。如果说
详细点,g(n)代表了搜索的广度的优先趋势。但是当h(n) >> g(n)
时,可以省略g(n),而提高效率。这些就深了, 不懂也不影响啦!
我们继续看看何谓A*算法。

二、初识A*算法:
启发式搜索其实有很多的算法,比如:局部择优搜索法、最好优先搜索
法等等。当然A*也是。这些算法 都使用了启发函数,但在具体的选取
最佳搜索节点时的策略不同。象局部择优搜索法,就是在搜索的过程
中 选取“最佳节点”后舍弃其他的兄弟节点,父亲节点,而一直得搜
索下去。这种搜索的结果很明显,由于舍 弃了其他的节点,可能也把
最好的节点都舍弃了,因为求解的最佳节点只是在该阶段的最佳并不
一定是全局 的最佳。最好优先就聪明多了,他在搜索时,便没有舍弃
节点(除非该节点是死节点),在每一步的估价中 都把当前的节点和
以前的节点的估价值比较得到一个“最佳的节点”。这样可以有效的
防止“最佳节点”的 丢失。那么A*算法又是一种什么样的算法呢?
其实A*算法也是一种最好优先的算法。只不过要加上一些约束 条件
罢了。由于在一些问题求解时,我们希望能够求解出状态空间搜索的
最短路径,也就是用最快的方法求 解问题,A*就是干这种事情的!
我们先下个定义,如果一个估价函数可以找出最短的路径,我们称之
为可采 纳性。A*算法是一个可采纳的最好优先算法。A*算法的估价
函数可表示为:
f'(n) = g'(n) + h'(n)
这里,f'(n)是估价函数,g'(n)是起点到终点的最短路径值,h'(n)是
n到目标的最断路经的启发值。由 于这个f'(n)其实是无法预先知道的
,所以我们用前面的估价函数f(n)做近似。g(n)代替g'(n),但
g(n)>=g'(n) 才可(大多数情况下都是满足的,可以不用考虑),
h(n)代替h'(n),但h(n)<=h'(n)才可(这一点特别的重 要)。可以
证明应用这样的估价函数是可以找到最短路径的,也就是可采纳的。
我们说应用这种估价函数的 最好优先算法就是A*算法。哈!你懂了吗?
肯定没懂!接着看!

举一个例子,其实广度优先算法就是A*算法的特例。其中g(n)是节点
所在的层数,h(n)=0,这种h(n)肯 定小于h'(n),所以由前述可知广
度优先算法是一种可采纳的。实际也是。当然它是一种最臭的A*算法。

再说一个问题,就是有关h(n)启发函数的信息性。h(n)的信息性通俗
点说其实就是在估计一个节点的值 时的约束条件,如果信息越多或约
束条件越多则排除的节点就越多,估价函数越好或说这个算法越好。
这就 是为什么广度优先算法的那么臭的原因了,谁叫它的h(n)=0,
一点启发信息都没有。但在游戏开发中由于实 时性的问题,h(n)的
信息越多,它的计算量就越大,耗费的时间就越多。就应该适当的减
小h(n)的信息,即 减小约束条件。但算法的准确性就差了,这里就
有一个平衡的问题。可难了,这就看你的了!

好了我的话也说得差不多了,我想你肯定是一头的雾水了,哈哈!
你还是找一本人工智能的书仔细看看吧!我这几百字是不足以将A*
算法讲清楚的。只是起到抛砖引玉的作用 希望大家热情参与!
预知A*算法的应用,请看姊妹篇《深入A*算法》
dengsf 2003-11-25
  • 打赏
  • 举报
回复
多谢saint001.
UP一下。
saint001 2003-11-23
  • 打赏
  • 举报
回复
所有的优化问题都可以考虑用模拟退火或者遗传算法来解决
入门的化建议买一本书
再考虑一个实际的优化问题,如何用模拟算法来求解
saint001 2003-11-23
  • 打赏
  • 举报
回复
模拟退火和遗传算法解决的都是优化问题,问题形式各种各样
往往有很大的规模,传统方法难以求得精确解
人们于是想设计各种各样的人工智能算法,模拟计算,得到可以认为满意的近似解

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧