编辑本段 概述
最大团问题(Maximum Clique Problem, MCP)是图论中一个经典的组合优化问题,也是一类NP完全问题,在国际上已有广泛的研究,而国内对MCP问题的研究则还处于起步阶段,因此,研究最大团问题具有较高的理论价值和现实意义。
最大团问题又称为最大 独立集问题(Maximum Independent Set Problem)。目前,求解MCP问题的 算法主要分为两类:确定性算法和 启发式算法。确定性算法有回溯法、 分支限界法等, 启发式算法 蚁群算法、顺序贪婪算法、DLS-MC算法和智能搜索算法等。
编辑本段 问题描述
给定无向图
G =(
V ,
E ),其中
V 是非空集合,称为顶点集;
E 是
V 中元素构成的无序二元组的集合,称为边集,无向图中的边均是顶点的无序对,无序对常用圆括号“( )”表示。如果
U ∈
V ,且对任意两个顶点
u ,
v ∈
U 有(
u ,
v )∈
E ,则称
U 是
G 的完全子图。
G 的完全子图
U 是
G 的团当且仅当
U 不包含在
G 的更大的完全子图中。
G 的最大团是指
G 中所含顶点数最多的团。
如果
U ∈V且对任意
u ,
v ∈
U 有(
u ,
v )不属于E,则称
U 是
G 的空子图。
G 的空子图
U 是
G 的 独立集当且仅当
U 不包含在
G 的更大的空子图中。
G 的最大 独立集是
G 中所含顶点数最多的独立集。
对于任一无向图
G =(
V ,
E ),其补图
G '=(
V ',
E ')定义为:
V '=
V ,且(
u ,
v )∈
E ' 当且仅当(
u ,
v )∉
E 。
如果
U 是
G 的完全子图,则它也是
G '的空子图,反之亦然。因此,
G 的团与
G '的 独立集之间存在一一对应的关系。特殊地,
U 是
G 的最大团当且仅当
U 是
G '的最大 独立集
。
编辑本段 应用背景
MCP问题是现实世界中一类真实问题,在市场分析、方案选择、信号传输、计算机视觉、故障诊断等领域具有非常广泛的应用。自1957年Hararv和Ross首次提出求解最大团问题的确定性算法以来,研究者们已提出了多种确定性算法来求解最大团问题。但随着问题规模的增大(顶点增多和边密度变大),求解问题的时间复杂度越来越高,确定性算法显得无能为力,不能有效解决这些NP完全问题。
20世纪80年代末,研究者们开始尝试采用 启发式算法求解最大团问题,提出了各种各样的启发式算法,如顺序贪婪启发式算法、 遗传算法、 模拟退火算法、禁忌搜索算法、 神经网络算法等,并且取得了令人满意的效果。在时间上,由于采用了启发式信息, 启发式算法的运算时间与确定性算法的运算时间之间的比值会随着图的顶点、边密度的增加而变得越来越小。唯一的缺点就是不一定能找到 最优值,有时只能找到近优值。
近年来研究表明,单独使用一种 启发式算法求解最大团问题,算法性能往往并不是很好,因此,常借鉴算法之间优势互补策略,形成新的混合启发式算法来求解最大团问题。当前求解该问题最好的 启发式算法有反作用 禁忌搜索(Reactive Tabu Search, RTS)算法、基于 遗传算法的简单启发式算法(Simple Heuristic Based Genetic Algorithm, HGA)、DLS-MC算法等。
编辑本段 常用算法
顺序贪婪启发式算法
顺序贪婪启发式算法是最早的求解最大团的启发式算法。这类算法通过给一个团重复进行加点操作得到一个极大团或者对一组并不是团的子图重复进行删除顶点操作以得到一个团。1987年,Kopf和Ruhe把这类型算法分为Best in和Worst out两类。
(1)Best in方法的基本思路:由一个团出发,和这个团中顶点相连的顶点组成候选集;然后以一定的启发式信息,从中选择顶点加入团中,以后反复进行,直到最后得到一个极大团。
(2)Worst out方法的基本思路:从整个顶点集开始,然后按一定的启发式信息,从中反复进行删除顶点操作,直到最后得到一个团。
顺序贪婪 启发式算法有很大不足,该算法一旦找见一个极大团,搜索就停止,因此找到最大团的概率相对较低。
局部搜索启发式算法
假设
SG 为图的所有极大团的集合,由于顺序贪婪启发式算法仅能找见
SG 中的一个极大团,因此,为了提高解的质量,应当扩大在
SG 的搜索区域,比如,可以在极大团
S 的邻居中继续进行搜索,以扩大搜索区域,进而提高解的质量。
在局部搜索 启发式算法中,如果搜索
S 的邻居越多,提高解的质量的机会就越大。依赖不同的邻居定义,局部搜索 启发式算法可以得到不同的解。在局部搜索 启发式算法中,比较有名的算法是
K -interchange启发式算法,它是一种基于
K -neighbor邻居实现的,在解集
S 的
K 邻居中进行局部搜索的方法。
分析可知,局部搜索 启发式算法存在一个问题,即仅能够找见一个局部 最优值。所以为了提高求解的质量,常把该算法和其它算法相混合,从而得到求解MCP问题的新的算法。
WaynePullan和HolgerH.Hoos基于这一思想提出了求解最大团问题的DLS-MC 算法,该算法是plateau search局部搜索启发式和算法迭代改善法相混合得到的,算法性能非常好,在该方法中引入了顶点 惩罚函数,该函数在算法的求解过程中能够动态改变;在算法执行过程中迭代改善法和plateau search算法轮流执行来提高解的质量。在基准图上对该 算法进行了测试,性能非常好。
智能搜索启发式算法
智能搜索算法主要有遗传算法、禁忌算法、模拟退火算法、神经网络等。
遗传算法
遗传算法(Genetic Algorithm, GA)是一种基于自然选择和群体遗传机理的搜索算法,它模拟了自然选择和自然遗传过程中发生的复制、交叉和变异现象。
1993年,Carter和Park首次提出使用 遗传算法求解最大团问题,但由于所求解的质量差,计算 复杂度高,因此,他们认为遗传算法并不适合求解最大团问题。与此同时,Bäck和Khuri致力于最大独立集问题的求解,却得到了完全相反的结论,通过选用合适的适应度函数,取得了很好的效果。因此在使用GA来解决最大团问题时, 适应度函数起着非常关键的作用。此后,基于 遗传算法求解最大团问题的方法逐渐增多,但在提高解的质量,降低算法复杂度上方面却没有大幅度的提高。
l998年,Marchiori提出了一种基于 遗传算法的简单 启发式算法(simple heuristic based genetic algorithm, HGA)。 算法由两部分组成:简单 遗传算法(simple genetic algorithm, SGA)和简单的贪婪启发式局部搜索算法(simple greedy heuristic local search algorithm,SGHLSA)。在基准图上对算法HGA的性能进行测试,证明了该算法在解的质量和计算速度方面都优于基于 遗传算法的其它算法。
因此,单纯使用 遗传算法(改动变异、 杂交、选择等算子)求解最大团问题时,算法的性能是比较差;要提高算法性能,遗传算法最好能和局部搜索算法相结合。
模拟退火算法
模拟退火(Simulated Annealing, SA)算法是N. Metropolis在1953年提出的一种基于物质退火过程的随机搜索算法,是一种迭代求解的启发式随机搜索算法。首先在 高温下较快地进行搜索,使系统进入“ 热平衡”状态,大致地找到系统的低能区域。随着温度的逐渐降低,搜索精度不断提高,可逐渐准确地找到最低 能量的 基态。作为局部搜索算法的扩展,当邻域的一次操作使当前解的质量提高时,接受这个改进解作为新的当前解;反之,以一定的概率接受相对质量比较差的解作为新的当前解。
Aarts和Korst提出使用 模拟退火算法来解决 独立集问题,建议在算法设计时引入 惩罚函数,但却没有提供任何的实验结果。问题的解空间
S 是图
G 的全部可能的子图,并不要求是 独立集,对于任一子图
G* ,成本函数为
f (
V ')=|
V '|- k|
E '|,其中
V '是图
G* 的顶点集,
E '是图
G* 的边集,k是权因子(k>1)。选择邻居时,费用值大的将被选中,因此求解最大 独立集问题也就是最大化成本函数问题。
Homer和Peinado把 模拟退火算法和Johnson的贪婪 启发式算法、Boppan的 随机化算法、Halldorsson的子图排除法3种启发式算法进行比较,结果比这3种算法要好很多。总之, 模拟退火算法在处理最大团问题上是一个非常好的算法。
禁忌算法
禁忌算法(Tabu Algorithm)是一种改进的局部搜索算法。该算法为了避免在搜索过程中出现死循环和开发新的搜索区域,采用了一种基于禁止的策略。
1989年,Friden提出了基于 禁忌搜索的求解最大 独立集的 启发式算法,独立集的大小固定,该算法的目标是最小化当前子集(解)顶点之间的边数。使用3个禁忌表:其中,一个禁忌表用来存放上一代的解,另外两个分别存放刚进入解顶点和刚被删去的顶点。
基于禁忌 算法求解最大团问题具有代表性的是Batti和Protasi提出的反作用局部搜索(Reaction Local Search, RLS)算法,通过引入局部搜索算法,扩展了 禁忌搜索的框架。与一般禁忌搜索算法相比,该算法的特点是:在执行过程中,根据所得到的解的情况形成一种内部 反馈机制以控制调整算法的控制参数,所以该算法的控制参数是动态变化的;比如,禁止表长度参数是动态变化的,因此禁忌表长度是动态变化的。他们在DIMACS的基准图上对 算法性能进行测试,取得非常好的效果。
神经网络算法
人工神经网络指为了模拟生物大脑的结构和功能而构成的一种大型的、分布式系统,它有很强的自组织性、自适应性和学习能力。
20个世纪80年代末期,Ballard、Godbeerl、Ramanujam和Sadayappan等都尝试对最大团和相关问题按 人工神经网络进行编码,进而求解该问题。然而,这些研究只提供了很少的实验结果。
Grossman提出一种离散的/确定性的Hopfield模型来求解最大团。这个模型有一个用来决定网络是否处于稳定态的临界值参数。Grossman建议在这个参数上使用退火策略,并且使用自适应机制选择网络的初始状态和临界值。在DIMACS基准图上测试,得到比较好的结果,但与性能好的 启发式算法相比,其结果较差,比如结果要差于 模拟退火算法。1995年Jagota对Hopfield模型进行了多处修改来近似求解最大团问题,其中有的是 离散化的,有的是连续的;虽然有了一定改进,但是性能并没有显著提高。随后,仍然有好多研究者使用Hopfield神经网络来求解最大团问题,但是与其它智能搜索 算法相比,效果比较差。
研究表明:(1) 前3种智能搜索 算法适合求解MCP,而通过 神经网络算法求解MCP时的性能比较差;(2) 单独使用智能搜索算法来求解MCP,算法性能并不好,因此,常和局部搜索算法相结合形成新的混合算法,比如:禁忌算法与局部搜索算法相混合形成的反作用禁忌搜索算法, 遗传算法与局部搜索算法相混合形成的简单 启发式算法等。
改进蚁群算法-AntMCP
蚁群算法是由Dorigo M.等人依据模仿真实的蚁群行为而提出的一种模拟进化算法。蚂蚁之间是通过一种称为 信息素(Pheromone)的 物质传递信息的,蚂蚁能够在经过的路径上留下该种物质,而且能够感知这种物质的存在及其强度,并以此来指导自己的 运动方向。因此,由大量蚂蚁组成的集体行为便表现出一种信息正反馈现象:某一条路径上走过的蚂蚁越多,该路径上留下的信息素就越多,则后来者选择该路径的 概率就越大。蚂蚁之间就是通过这种信息素的交流,搜索到一条从 蚁巢到食物源的最短路径。
2003年,Fenet和Solnon提出了求解最大团问题的 蚁群算法AntClique,该算法仍然将信息素留在边上,信息素t
ij 是指把结点
i 和结点
j 分配到同一个团中的期望。由于没有使用局部启发信息,这使得迭代初期各候选顶点的选择概率几乎相等,这样算法在迭代初期有一定的盲目性,往往需要更多的迭代次数才能得到 最优解。针对这些不足及最大团问题的特点,曾艳于2010年提出了改进的 蚁群算法-AntMCP。
算法伪代码描述如下:
Procedure Vertex_AntClique
Initialize //初始化信息素和局部启发信息
Repeat
For
k in 1...nbAnts do:
Choose randomly a first vertex
v f∈ V
Ck← {
v f }
Candidate ¬{
v i | (
v f ,
v i )
∈E }
While Candidate≠0 do
Choose a vertex
v i∈ Candidate withprobability
p (
v i );
Ck ←
Ck ∪{
v i }
Candidate ←Candidate ∩{
v j | (
vi ,
v j )
∈E }
End of while
Endof for
Updatepheromone w.r.t {C1,…,CnbAnts}
Until max cyclesreached or optimal solution found
End of procedure
在AntMCP中,增加了局部启发信息;信息素t和启发信息h不是留在边上,而是留在顶点上。这样,变量t和h由二维降为一维,既可节省存储空间,又可提高运行速度,大量实验表明,该算法运算速度更快,效率更高。
其它启发式算法
除上述几种启发式算法外,目前研究者们还提出了一些新的算法。当图的顶点数不大于阈值
M 时,称此图为低度图,求解低度图的最大团问题的时间复杂度为
O (
d ),基于这一思想,王青松和范铁生提出了一种求解低度图的最大团的确定性算法。在该算法中,通过对图按顶点逐步分解实现分别计算,较好地解决了低度图的最大团问题,算法的时间复杂度为
O (
d*n^3 )。针对遗传算法在最大团求解中保持群体多样性能力不足、早熟、耗时长、成功率高等缺陷,依据均匀设计抽样理论对交叉操作进行重新设计,结合免疫机理定义染色体浓度设计克隆选择策略,周本达、岳芹等提出了一种求解最大团问题的均价设计抽样免疫遗传算法。仿真算例表明,该算法在解的质量、收敛速度等各项指标上均有提高,与DLS-MC、QUALEX等经典搜索算法相比,对部分算例能得到更好解。吴冬辉和马良提出了基于遗传算法的最大团问题求解算法,通过引入概率模型指导变异产生新的个体,并结合启发式局部算法搜索最大团。实例结果验证了该算法的有效性。针对求解最大团问题的分层的边权网络(Hierarchical Edge-Weight Network,HEWN)算法,郭长庚和潘晓伟设计了一个实现HEWN算法的数据结构,指出在HEWN算法中HEWN算法的存储宜采用邻接多重表和二叉表相结合的链表表示法,并进行了时间复杂度分析,得出HEWN算法的时间复杂度是指数级而不是
O (
n^8.5) 。针对基于适应值的选择交叉机制在优化具有欺骗性的最大团问题中性能退化的问题,张雁、党群等提出了一种新的基于匹配教程的Memetic算法。算法中提出交叉匹配度的概念,用来估计两个体交叉所能获得的最佳适应值。通过匹配度的计算对交叉方向的选择进行控制,保证了交叉操作以较大的概率生成新的优良模式。测试结果表明,该算法优于目前在最大团问题求解中性能最好的多阶段动态局部搜索算法。DNA计算是应用分子生物技术进行计算的新方法,具有高度并行性、大容量、低能耗等特点。针对这一特点,李涛提出了用DNA算法求解最大团问题,开创了以生物技术为工具解决复杂问题的新纪元,为解决NP完全问题开辟了一条新途径。基于对粘贴模型的组成、基本实验及其生化实现过程的分析,根据最大团问题的需求,周康、刘朔等在粘贴模型中,提出了基于电泳技术和分离实验的DNA序列检测方法。基于分离实验提出了一种求解最大团问题的DNA算法,并给出了其生化实现过程。为了提高交叉熵算法求解最大团问题的性能,吕强、柏战华等提出了一种领导者-跟随者协作求解的并行策略来实现交叉熵算法,从而达到减少计算时间和保障解的质量两者的平衡。算法中领导者活跃在并行处理器之间采集数据,并根据当前获得信息对跟随者作出决策;受控的跟随者则主要根据领导者的决策信息自适应地调整搜索空间,完成各自的集团产生任务。实验结果表明该算法较基于种群的启发式算法有一定的性能改善。
回溯法
回溯法(BacktrackingAlgorithm, BA)有“通用的解题法”之称,用它可以系统地搜索一个问题的所有解或任一解,是一个既带有系统性又带有跳跃性的搜索算法。在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解,如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按照深度优先的策略进行搜索。BA在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。而BA在用来求问题的任一解时,只要搜索到问题的一个解即可结束。这种以深度优先的方式系统地搜索问题的解的算法称为回溯法,它适用于解一些组合数较大的问题。
回溯法搜索 解空间树时,根节点首先成为一个活结点,同时也成为当前的扩展节点。在当前扩展节点处,搜索向纵深方向移至一个新节点。这个新节点就成为一个新的活结点,并成为当前扩展节点。如果当前扩展节点不能再向纵深方向移动,则当前的扩展节点就成为死结点。此时,往回回溯至最近的一个活节点处,并使这个活结点成为当前的扩展节点。
回溯法以这种方式递归地在 解空间中搜索,直至找到所有要求的解或解空间已无活结点为止。
搜索:回溯法从根结点出发,按深度优先策略遍历解空间树,搜索满足约束条件的解。
剪枝:在搜索至树中任一结点时,先判断该结点对应的部分解是否满足 约束条件,或者是否超出 目标函数的界;也即判断该结点是否包含问题的解,如果肯定不包含,则跳过对以该结点为根的子树的搜索,即剪枝(Pruning);否则,进入以该结点为根的子树,继续按照深度优先的策略搜索。
一般来讲,回溯法求解问题的基本步骤如下:
(1)针对所给问题,定义问题的 解空间;确定易于搜索的解空间结构;以深度优先方式搜索解空间,并在搜索过程中利用Pruning函数剪去无效的搜索。
(2) 无向图
G 的最大团问题可以看作是图
G 的顶点集
V 的子集选取问题。因此可以用子集树表示问题的 解空间。设当前扩展节点
Z 位于 解空间树的第
i 层。在进入左子树前,必须确认从顶点
i 到已入选的顶点集中每一个顶点都 有边相连。在进入右子树之前,必须确认还有足够多的可选择顶点使得 算法有可能在右子树中找到更大的团。
(3)用 邻接矩阵表示图
G ,
n 为
G 的顶点数,
cn 存储当前团的顶点数,
bestn 存储最大团的顶点数。
cn+n-i 为进入右子树的上界 函数,当
cn+n-i <
bestn 时,不能在右子树中找到更大的团,利用剪枝函数可将
Z 的右结点剪去。
实例分析
图1
如图1所示,给定无向图
G ={
V ,
E },其中
V ={1,2,3,4,5},
E ={(1,2), (1,4), (1,5),(2,3), (2,5), (3,5), (4,5)}。根据MCP定义,子集{1,2}是图
G 的一个大小为2的完全子图,但不是一个团,因为它包含于
G 的更大的完全子图{1,2,5}之中。{1,2,5}是
G 的一个最大团。{1,4,5}和{2,3,5}也是
G 的最大团。图2是无向图
G 的补图
G '。根据最大独立集定义,{2,4}是
G 的一个空子图,同时也是
G 的一个最大独立集。虽然{1,2}也是
G '的空子图,但它不是
G '的独立集,因为它包含在
G '的空子图{1,2,5}中。{1,2,5}是
G '的最大独立集。{1,4,5}和{2,3,5}也是
G '的最大
图2
独立集。以图1为例,利用回溯法搜索其空间树,具体搜索过程(见图3所示)如下:假设我们按照1®2®3®4®5的顺序深度搜索。开始时,根结点
R 是唯一活结点,也是当前扩展结点,位于第1层,此时当前团的顶点数
cn =0,最大团的顶点数
bestn =0。在这个扩展结点处,我们假定
R 和第二层的顶点1之间有边相连,则沿纵深方向移至顶点1处。此时结点
R 和顶点1都是活结点,顶点1成为当前的扩展结点。此时当前团的顶点数
cn =1,最大团的顶点数
bestn =0。继续深度搜索至第3层顶点2处,此时顶点1和2有边相连,都是活结点,顶点2成为当前扩展结点。此时当前团的顶点数
cn =2,最大团的顶点数
bestn =0。再深度搜索至第4层顶点3处,由于顶点3和2有边相连但与顶点1无边相连,则利用剪枝函数剪去该枝,此时由于
cn+n-i =2+5-4=3>
bestn =0,则回溯到结点2处进入右子树,开始搜索。此时当前团的顶点数
cn =2,最大团的顶点数
bestn =0。再深度搜索至第5层顶点4处,由于顶点3和4无边相连,剪去该枝,回溯到结点3处进入右子树,此时当前团的顶点数
cn =2,最大团的顶点数
bestn =0。继续深度搜索至第6层顶点5处,由于顶点5和4有边相连,且与顶点1和2都有边相连,则进入左子树搜索。由于结点5是一个叶结点,故我们得到一个可行解,此时当前团的顶点数
cn =3,最大团的顶点数
bestn =3。
vi 的取值由顶点1至顶点5所唯一确定,即
v =(1, 2, 5)。此时顶点5已不能再纵深扩展,成为死结点,我们返回到结点4处。由于此时
cn+n-i =3+5-6=2<
bestn =3,不能在右子树中找到更大的团,利用剪枝函数可将结点4的右结点剪去。以此回溯,直至根结点
R 再次成为当前的扩展结点,沿着右子树的纵深方向移动,直至遍历整个解空间。最后得到图1的按照1®2®3®4®5的顺序深度搜索的最大团为
U ={1,2,5}。当然{1,4,5}和{2,3,5}也是其最大团。
图3
C++ 代码
//MaxClique.cpp : 定义控制台应用程序的入口点。
/*
回溯法求解最大团问题
*/
#include
#include
#include
#include
using namespace std;
#define MAX_v 50 //定义一个最大顶点个数
typedef struct{
int a[MAX_v][MAX_v]; //无向图G的邻接矩阵
int v; //无向图G的顶点
int e; //无向图G的边
int x[50]; //顶点与当前团的连接,x[i]=1 表示有连接
int bestx[50]; //当前最优解
int cnum; //当前团的顶点数目
int bestn; //最大团的顶点数目
}MCP;
void Creat(MCP &G);
void Backtrack(MCP &G,int i);
void Creat(MCP &G){
int i,j;
ifstream fin("data.txt");
if (!fin)
{
cout<<"不能打开文件:"<<"data.txt"<
exit(1);
}
fin>>G.v;
for (int i=1;i<=G.v;i++)
for (int j=1;j<=G.v;j++)
fin>>G.a[i][j];
for(i=1;i<=G.v;i++) //初始化
{
G.bestx[i]=0;
G.x[i]=0;
G.bestn=0;
G.cnum=0;
}
cout<<"————————————————"<
cout<<"———回溯法求解最大团问题———"<
cout<<"————————————————"<
cout<<"输入初始化无向图矩阵为:"<
for(i=1;i<=G.v;i++)
{
for(j=1;j<=G.v;j++)
cout<
cout<
}
}
void Backtrack(MCP &G,int i){
if (i>G.v){
for (int j=1; j<=G.v; j++)
G.bestx[j] = G.x[j];
G.bestn =G.cnum;
return ;
}
//检查顶点i与当前团的连接
int OK = 1;
for (int j=1; j<=i ; j++)
if (G.x[j]&& G.a[i][j]==0){
//i不与j相连
OK = 0;
break;
}
if (OK) {
G.x[i] = 1;//把i加入团
G.cnum++;
Backtrack(G,i+1);
G.x[i]=0;
G.cnum-- ;
}
if (G.cnum+G.v- i>G.bestn){
G.x[i] = 0;
Backtrack(G,i+1);
}
}
int main(){
MCP G;
Creat(G);
Backtrack(G,1);
cout<<"最大团包含的顶点数为:"<
cout<<"最大团方案为:( ";
for (int i=1;i<=G.v;i++)
if(G.bestx[i]==1){
cout<
}
cout<<")"<
getch();
}
分支限界法
分支限界(Brandand Bound)法类似于回溯法,也是一种在问题的 解空间树上搜索问题的解的算法。
分支限界法常以广度优先或最小耗费(最大效益)优先的方式搜索解空间树。在 分支限界法中,每一个活结点只有一次机会成为扩展结点。一旦活结点成为扩展结点,就一次性产生其所有儿子结点。在这些儿子结点中,舍弃那些导致不可行解或导致非 最优解的儿子结点,将其余儿子结点加入活结点表中。此后,从活结点表中取下一个结点成为当前扩展结点,并重复上述结点扩展过程,直至找到所需的解或活结点表为空时为止。
具体来讲, 分支限界法由“分支”策略和“限界”策略两部分组成。“分支”体现在对问题空间是按广度优先搜索;“限界”策略是为了加速搜索速度而采用启发式剪枝的策略。分支搜索法采用广度优先的策略,依次生成E结点所有分支(即所有的子结点)。在生成的结点中,将采用更有效的约束函数(限界函数)控制搜索路径,去除那些不满足 约束条件(即不可能导出 最优解)的结点,使之能更好地朝着 状态空间树上有最优解的分支推进。
根据从活结点表中选择下一个扩展结点的方式的不同, 分支限界法主要分为以下两类:
1.队列式(FIFO) 分支限界法
队列式 分支限界法将活结点表组织成一个队列,并按队列的FIFO原则选取下一个结点成为当前扩展结点。具体流程为:
A.初始化,根结点是唯一的活结点,根结点入队。
B.从活结点队中取出根结点后,作为当前E结点。对当前E结点,先从左到右地产生它的所有儿子,用约束条件检查,把所有满足约束 函数的儿子加入活结点队列中。
C.重复上述过程:再从活结点表中取出队首结点(队中最先进来的结点)为当前E结点,……;直到找到一个解或活结点队列为空为止。
2.优先队列式 分支限界法
优先队列式 分支限界法将活结点表组织成一个优先队列,并按优先队列中规定的结点优先级选取优先级最高的下一个结点成为当前扩展结点。具体流程为:对每一活结点计算一个优先级,并根据这些优先级,从当前活结点表中优先选择一个优先级最高(最有利)的结点作为扩展结点,使搜索朝着解空间树上有 最优解的分支推进,以便尽快地找出一个最优解。
C++ 代码
//MaxClique_BB.cpp : 定义控制台应用程序的入口点。
/*
分支限界法求解最大团问题
*/
#include
#include
#include
#include
using namespace std;
typedef struct{
int v; //无向图G的顶点
int e; //无向图G的边
int a[50][50]; //定义图G的邻接矩阵
int bestx[50]; //最优解
}MCP;
void Creat(MCP &G){
int i,j;
ifstream fin("data.txt");
if(!fin)
{
cout<<"不能打开文件:"<<"data.txt"<
exit(1);
}
fin>>G.v;
for(int i=1;i<=G.v;i++)
for(int j=1;j<=G.v;j++)
fin>>G.a[i][j];
for(i=1;i<=G.v;i++) //初始化
{
G.bestx[i]=0;
}
cout<<"————————————————————————"<
cout<<"———优先队列式 分支限界法求解最大团问题———"<
cout<<"————————————————————————"<
cout<<"输入初始化无向图矩阵为:"<
for(i=1;i<=G.v;i++)
{
for(j=1;j<=G.v;j++)
cout<
cout<
}
}
struct BBNode
{
BBNode *parent; //指向父结点的指针
bool LChild; //左儿子结点标志
};
struct CliqueNode //定义优先队列类型为CliqueNode
{
int cnum; //当前团的顶点数
int un; //当前团最大顶点数的上界
int level; //结点在子集空间树种所处的层次
BBNode *p; //指向活结点在子集树中相应结点的指针
bool operator<(const CliqueNode &b) const //<号重载建立大根堆
{
if (b.un>un) return true;
if (b.un==un&& b.cnum>cnum) return true;
else return false;
}
};
void BBMaxClique(MCP&G)
{
BBNode *E=new(BBNode); //定义B代表记录的队列情况
//初始化
int j,i=1;
int cnum=0,bestn=0;
int OK=1;
priority_queue Q; //定义优先队列Q
E->LChild=false; //初始化
E->parent=NULL;
while(i!=G.v+1)//非 叶结点
{
//检查顶点i与当前团中其它顶点之间是否 有边相连
OK=1;
BBNode *B=E; //把当前点的数据给B,B为中间变量
for(j=i-1;j>0;B=B->parent,j--)
if(B->LChild&& G.a[i][j]==0) //如果不满足就停止
{
OK=0;
break;
}
if(OK) //满足条件,即左儿子结点为可行结点
{
CliqueNode *D=new(CliqueNode); //定义一个节点D
D->p=new(BBNode);
if(cnum+1>bestn)bestn=cnum+1;
D->cnum=cnum+1;
D->level=i+1;
D->p->LChild=true;
D->p->parent=E;
D->un=cnum+1+G.v-i;
Q.push(*D); //进队列
}
if(cnum+G.v-i>bestn) //不满足条件但是还是可能有最优解
{
CliqueNode *D=new(CliqueNode); //定义一个节点D
D->p=new(BBNode);
D->cnum=cnum;
D->level=i+1;
D->p->LChild=false;
D->p->parent=E;
D->un=cnum+G.v-i;
Q.push(*D); //进队列
}
CliqueNode N;
N=Q.top(); //取队顶元素,最大堆
Q.pop(); //删除队顶元素
E=N.p; //记录当前团的信息
cnum=N.cnum; //记录当前团的顶点数
i=N.level; //所在的层次
}
for(j=G.v;j>0;j--) //保存最优解
{
G.bestx[j]=E->LChild;
E=E->parent;
bestn=cnum;
}
}
int main(){
MCP G;
Creat(G);
BBMaxClique(G);
cout<<"最大团方案为:(";
for(int i=G.v;i>0;i--)
if (G.bestx[i]==1){
cout<
}
cout<<")"<
getch();
}
[1]
poj1129_四色问题
题意:染色问题,图中之间有边的两个区域不能染成相同的颜色。求将图中每个区域全部染色后需要最少的颜色。 分析:参考染色定理得,无论图中有多少区域,最多需要4个区域。因此遍历这四种情况即可. 代码:
View Code
1 #include
2 #include
3 #include
4 using namespace std;
5
6 const int maxnum=27 ;
7 bool array[maxnum][maxnum];
8 int num;
9
10 void fuction()
11 {
12 int i,j,k,l;
13 for (i=1 ;i<=num;i++)
14 for (j=1 ;j<=num;j++)
15 for (k=1 ;k<=num;k++)
16 for (l=1 ;l<=num;l++)
17 if (array[i][j]&&array[i][k]&&array[i][l]&&array[j][k]&&array[j][l]&&array[k][l])
18 {
19 printf(" 4 channels needed.\n " );
20 return ;
21 }
22 for (i=1 ;i<=num;i++)
23 for (j=1 ;j<=num;j++)
24 for (k=1 ;k<=num;k++)
25 if (array[i][j]&& array[i][k]&&array[j][k])
26 {
27 printf(" 3 channels needed.\n " );
28 return ;
29 }
30 for (i=1 ;i<=num;i++)
31 for (j=1 ;j<=num;j++)
32 if (array[i][j])
33 {
34 printf(" 2 channels needed.\n " );
35 return ;
36 }
37 printf(" 1 channel needed.\n " );
38 }
39
40 int main()
41 {
42 int i;
43 bool flag;
44 char ch,tch;
45 while (scanf(" %d " ,&num)!=EOF)
46 {
47 if (num==0 ) break ;
48 memset(array,false ,sizeof (array));
49 flag=false ;
50 getchar();
51 for (i=0 ;i52 {
53 scanf(" %c%c " ,&ch,&tch);
54 int a=ch-' A ' +1 ;
55 while (scanf(" %c " ,&ch)!=EOF)
56 {
57 if (ch==' \n ' ) break ;
58 int b=ch-' A ' +1 ;
59 array[a][b]=true ;
60 array[b][a]=true ;
61 }
62 }
63 fuction();
64 }
65 return 0 ;
66 }
另一种方法是最大团,我用最大团做完之后发现,其实这个题用最大团的解法是错误的。比如:
5 A:BE B:AC C:BD D:CE E:AD
这组数据用最大团做,ans=2,但是这个题的答案应该是3.可见这个题的数据有问题,最大团的代码见下、
View Code
1 #include
2 #include
3 #include
4 using namespace std;
5 // 148K 0MS
6
7 const int maxnum=27 ;
8 bool array[maxnum][maxnum];
9 int use[maxnum];
10 int num,cn,bestn;
11
12
13 void dfs(int i)
14 {
15 if (i>num)
16 {
17 bestn=cn;
18 return ;
19 }
20 bool flag=true ;
21 int j;
22 for (j=1 ;j23 if (use[j] && !array[j][i])
24 {
25 flag=false ;
26 break ;
27 }
28 if (flag)
29 {
30 cn++;
31 use[i]=true ;
32 dfs(i+1 );
33 cn--;
34 use[i]=false ;
35 }
36 if (cn+num-i>bestn)
37 {
38 use[i]=false ;
39 dfs(i+1 );
40 }
41 }
42
43 int main()
44 {
45 int i;
46 char ch,tch;
47 while (scanf(" %d " ,&num)&& num!=0 )
48 {
49 memset(array,false ,sizeof (array));
50 memset(use,false ,sizeof (use));
51 cn=0 ;
52 bestn=0 ;
53 getchar();
54 for (i=0 ;i55 {
56 scanf(" %c%c " ,&ch,&tch);
57 int a=ch-' A ' +1 ;
58 while (scanf(" %c " ,&ch) && ch!=' \n ' )
59 {
60 int b=ch-' A ' +1 ;
61 array[a][b]=true ;
62 array[b][a]=true ;
63 }
64 }
65 dfs(1 );
66 if (bestn==1 )
67 printf(" 1 channel needed.\n " );
68 else
69 printf(" %d channels needed.\n " ,bestn);
70 }
71 return 0 ;
72 }
73 /*
74 6
75 A:BEF
76 B:AC
77 C:BD
78 D:CEF
79 E:ADF
80 F:ADE
81 */
tju oj 1077
poj3692_最大团_二分图
题意:已知班级有g个女孩和b个男孩,所有女生之间都相互认识,所有男生之间也相互认识,给出m对关系表示哪个女孩与哪个男孩认识。现在要选择一些学生来组成一个团,使得里面所有人都认识,求此团最大人数。
思路:最大团问题。
定理:
原图的最大团=补图的最大独立集
原图的最大独立集=补图的最大团。
由于这个题的补图显然是一个二分图,而二分图的补图的最大独立集可以由匈牙利算法求的,所以该题的最大团问题可以转化成补图的最大独立集来做。
代码:
View Code
1 #include
2 #include
3 #include
4 using namespace std;
5 const int maxnum=201 ;
6 bool array[maxnum][maxnum];
7 bool use[maxnum];
8 int res[maxnum];
9 int b,g,m;
10
11 bool find(int i)
12 {
13 int j;
14 for (j=1 ;j<=b;j++)
15 {
16 if (!use[j] && array[i][j])
17 {
18 use[j]=true ;
19 if (res[j]==0 || find(res[j]))
20 {
21 res[j]=i;
22 return true ;
23 }
24 }
25 }
26 return false ;
27 }
28
29 int main()
30 {
31 int p,q;
32 int i,ans;
33 int k=0 ;
34 while (scanf(" %d%d%d " ,&g,&b,&m)!=EOF)
35 {
36 if (g==0 && b==0 && m==0 )
37 break ;
38 memset(array,true ,sizeof (array));
39 memset(res,0 ,sizeof (res));
40 for (i=0 ;i41 {
42 scanf(" %d%d " ,&p,&q);
43 array[p][q]=false ; // 补图
44 }
45 ans=0 ;
46 for (i=1 ;i<=g;i++)
47 {
48 memset(use,false ,sizeof (use));
49 if (find(i))
50 ans++;
51 }
52 k++;
53 printf(" Case %d: %d\n " ,k,b+g-ans);
54 }
55 return 0 ;
56 }
poj1419_染色_最大独立集_最大团
题意:
经典的图的染色问题,求对于给定的无向图中,给每个结点染两种不同颜色(黑色和白色)的一种且相邻结点的颜色不同,求染成黑色的最多结点数。
分析:
这个题求的图的最大独立集,最大独立集即为黑色节点的个数。
由于原图的最大独立集=补图的最大团。
而这个题是普通图,所以用回溯法来做,时间复杂度O(n*2^n)
代码:
View Code
1 #include
2 #include
3 #include
4 using namespace std;
5
6 const int maxnum=101 ;
7 bool array[maxnum][maxnum];
8 bool use[maxnum]; // 进入团的标号
9 bool bestx[maxnum];
10 int cn,bestn,p,e;
11
12 void dfs(int i)
13 {
14 int j;
15 bool flag;
16
17 if (i>p)
18 {
19 bestn=cn; // cn的值是递增的
20 // printf("%d\n",bestn);
21 // for(j=1;j<=p;j++)
22 // if(use[j])
23 // printf("%d ",j);
24 // printf("\n"); 在这里输出不一定是最大团
25 for (j=1 ;j<=p;j++) // 而是应该赋值给另外一个数组,
26 bestx[j]=use[j];
27 return ;
28 }
29
30 flag=true ;
31 for (j=1 ;j32 if (use[j]&&!array[j][i])
33 {
34 flag=false ;
35 break ;
36 }
37 if (flag)
38 {
39 cn++;
40 use[i]=true ;
41 dfs(i+1 );
42 cn--;
43 }
44 if (cn+p-i>bestn) // 剪枝
45 {
46 use[i]=false ;
47 dfs(i+1 );
48 }
49 }
50
51 int main()
52 {
53 int num,i,u,v;
54 scanf(" %d " ,&num);
55 while (num--)
56 {
57 memset(array,true ,sizeof (array));
58 memset(use,false ,sizeof (use));
59 memset(bestx,false ,sizeof (bestx));
60 scanf(" %d%d " ,&p,&e);
61 for (i=0 ;i62 {
63 scanf(" %d%d " ,&u,&v);
64 array[u][v]=false ;
65 array[v][u]=false ;
66 }
67
68 cn=bestn=0 ;
69 dfs(1 );
70 printf(" %d\n " ,bestn);
71 for (i=1 ; i<=p; i++)
72 if (bestx[i])
73 printf(" %d " ,i);
74 printf(" \n " );
75 }
76
77 return 0 ;
78 }
79
80 /*
81 1
82 5 7
83 1 2
84 1 4
85 1 5
86 2 3
87 2 5
88 3 5
89 4 5
90 */
最大团
问题描述:团就是最大完全子图。
给定无向图G=(V,E)。如果U V,且对任意u,v U 有(u,v) E,则称U 是G 的完全子图。
G 的完全子图U是G的团当且仅当U不包含在G 的更大的完全子图中,即U就是最大完全子图。
G 的最大团是指G中所含顶点数最多的团。
例如:
(a) (b) (c) (d)
图a是一个无向图,图b、c、d都是图a的团,且都是最大团。
求最大团的思路:
首先设最大团为一个空团,往其中加入一个顶点,然后依次考虑每个顶点,查看该顶点加入团之后仍然构成一个团,如果可以,考虑将该顶点加入团或者舍弃两种情况,如果不行,直接舍弃,然后递归判断下一顶点。对于无连接或者直接舍弃两种情况,在递归前,可采用剪枝策略来避免无效搜索。
为了判断当前顶点加入团之后是否仍是一个团,只需要考虑该顶点和团中顶点是否都有连接。
程序中采用了一个比较简单的剪枝策略,即如果剩余未考虑的顶点数加上团中顶点数不大于当前解的顶点数,可停止继续深度搜索,否则继续深度递归
当搜索到一个叶结点时,即可停止搜索,此时更新最优解和最优值。
以下是转载的某篇论文的,百度文库的
http://wenku.baidu.com/view/1bd93526a5e9856a561260e2.html
3.6 回溯法
3.6.1 算法基本思想
回溯法(Backtracking Algorithm, BA)有“通用的解题法”之称,用它可以系统地搜索一个问题的所有解或任一解,是一个既带有系统性又带有跳跃性的搜索算法。在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解,如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按照深度优先的策略进行搜索。BA在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。而BA在用来求问题的任一解时,只要搜索到问题的一个解即可结束。这种以深度优先的方式系统地搜索问题的解的算法称为回溯法,它适用于解一些组合数较大的问题。
回溯法搜索解空间树时,根节点首先成为一个活结点,同时也成为当前的扩展节点。在当前扩展节点处,搜索向纵深方向移至一个新节点。这个新节点就成为一个新的活结点,并成为当前扩展节点。如果当前扩展节点不能再向纵深方向移动,则当前的扩展节点就成为死结点。此时,往回回溯至最近的一个活节点处,并使这个活结点成为当前的扩展节点。
回溯法以这种方式递归地在解空间中搜索,直至找到所有要求的解或解空间已无活结点为止。
3.6.2 算法设计思想
搜索:回溯法从根结点出发,按深度优先策略遍历解空间树,搜索满足约束条件的解。
剪枝:在搜索至树中任一结点时,先判断该结点对应的部分解是否满足约束条件,或者是否超出目标函数的界;也即判断该结点是否包含问题的解,如果肯定不包含,则跳过对以该结点为根的子树的搜索,即剪枝(Pruning);否则,进入以该结点为根的子树,继续按照深度优先的策略搜索。
一般来讲,回溯法求解问题的基本步骤如下:
(1) 针对所给问题,定义问题的解空间;
(2) 确定易于搜索的解空间结构;
(3) 以深度优先方式搜索解空间,并在搜索过程中利用Pruning函数剪去无效的搜索。
无向图G 的最大团问题可以看作是图G 的顶点集V 的子集选取问题。因此可以用子集树表示问题的解空间。设当前扩展节点Z 位于解空间树的第i 层。在进入左子树前,必须确认从顶点i 到已入选的顶点集中每一个顶点都有边相连。在进入右子树之前,必须确认还有足够多的可选择顶点使得算法有可能在右子树中找到更大的团。
用邻接矩阵表示图G ,n 为G 的顶点数,cn 存储当前团的顶点数,bestn 存储最大团的顶点数。cn+n-i 为进入右子树的上界函数,当cn+n-i <bestn 时,不能在右子树中找到更大的团,利用剪枝函数可将Z 的右结点剪去。
3.6.3 实例分析
如图1所示,给定无向图G ={V , E },其中V ={1,2,3,4,5},E ={(1,2), (1,4), (1,5), (2,3), (2,5), (3,5), (4,5)}。根据MCP定义,子集{1,2}是图G 的一个大小为2的完全子图,但不是一个团,因为它包含于G 的更大的完全子图{1,2,5}之中。{1,2,5}是G 的一个最大团。{1,4,5}和{2,3,5}也是G 的最大团。
图2是无向图G 的补图G '。根据最大独立集定义,{2,4}是G 的一个空子图,同时也是G 的一个最大独立集。虽然{1,2}也是G '的空子图,但它不是G '的独立集,因为它包含在G '的空子图{1,2,5}中。{1,2,5}是G '的最大独立集。{1,4,5}和{2,3,5}也是G '的最大独立集。
以图1为例,利用回溯法搜索其空间树,具体搜索过程(见图3所示)如下:假设我们按照1®2®3®4®5的顺序深度搜索。开始时,根结点R 是唯一活结点,也是当前扩展结点,位于第1层,此时当前团的顶点数cn =0,最大团的顶点数bestn =0。在这个扩展结点处,我们假定R 和第二层的顶点1之间有边相连,则沿纵深方向移至顶点1处。此时结点R 和顶点1都是活结点,顶点1成为当前的扩展结点。此时当前团的顶点数cn =1,最大团的顶点数bestn =0。继续深度搜索至第3层顶点2处,此时顶点1和2有边相连,都是活结点,顶点2成为当前扩展结点。此时当前团的顶点数cn =2,最大团的顶点数bestn =0。再深度搜索至第4层顶点3处,由于顶点3和2有边相连但与顶点1无边相连,则利用剪枝函数剪去该枝,此时由于cn+n-i =2+5-4=3>bestn =0,则回溯到结点2处进入右子树,开始搜索。此时当前团的顶点数cn =2,最大团的顶点数bestn =0。再深度搜索至第5层顶点4处,由于顶点3和4无边相连,剪去该枝,回溯到结点3处进入右子树,此时当前团的顶点数cn =2,最大团的顶点数bestn =0。继续深度搜索至第6层顶点5处,由于顶点5和4有边相连,且与顶点1和2都有边相连,则进入左子树搜索。由于结点5是一个叶结点,故我们得到一个可行解,此时当前团的顶点数cn =3,最大团的顶点数bestn =3。vi 的取值由顶点1至顶点5所唯一确定,即v =(1, 2, 5)。此时顶点5已不能再纵深扩展,成为死结点,我们返回到结点4处。由于此时cn+n-i =3+5-6=2<bestn =3,不能在右子树中找到更大的团,利用剪枝函数可将结点4的右结点剪去。以此回溯,直至根结点R 再次成为当前的扩展结点,沿着右子树的纵深方向移动,直至遍历整个解空间。最后得到图1的按照1®2®3®4®5的顺序深度搜索的最大团为U ={1,2,5}。当然{1,4,5}和{2,3,5}也是其最大团。
代码:
View Code
1 #include
2 #include
3 #include
4 using namespace std;
5
6 const int maxnum=101 ;
7 bool array[maxnum][maxnum];
8 bool use[maxnum]; // 进入团的标号
9 int cn,bestn,p,e;
10
11 void dfs(int i)
12 {
13 int j;
14 bool flag;
15
16 if (i>p)
17 {
18 bestn=cn;
19 printf(" %d\n " ,bestn);
20 for (j=1 ;j<=p;j++)
21 if (use[j])
22 printf(" %d " ,j);
23 printf(" \n " );
24 return ;
25 }
26
27 flag=true ;
28 for (j=1 ;j29 if (use[j]&&!array[j][i])
30 {
31 flag=false ;
32 break ;
33 }
34 if (flag)
35 {
36 cn++;
37 use[i]=true ;
38 dfs(i+1 );
39 cn--;
40 }
41 if (cn+p-i>bestn) // 剪枝
42 {
43 use[i]=false ;
44 dfs(i+1 );
45 }
46 }
47
48 int main()
49 {
50 int num,i,u,v;
51 scanf(" %d " ,&num);
52 while (num--)
53 {
54 memset(array,false ,sizeof (array));
55 memset(use,false ,sizeof (use));
56 scanf(" %d%d " ,&p,&e);
57 for (i=0 ;i58 {
59 scanf(" %d%d " ,&u,&v);
60 array[u][v]=true ;
61 array[v][u]=true ;
62 }
63
64 cn=bestn=0 ;
65 dfs(1 );
66 // printf("%d\n",bestn);
67 }
68
69 return 0 ;
70 }
71
72 /*
73 1
74 5 7
75 1 2
76 1 4
77 1 5
78 2 3
79 2 5
80 3 5
81 4 5
82 */
你可能感兴趣的:(算法)
dfs专题五:FloodFill算法
lisanndesu
算法 深度优先
1.图像渲染link:733.图像渲染-力扣(LeetCode)codeclassSolution{public:intprev;vector>floodFill(vector>&image,intsr,intsc,intcolor){if(image[sr][sc]==color)returnimage;prev=image[sr][sc];dfs(image,sr,sc,color);retu
分形、大自然的分形几何、数据可视化、Python绘图
timedot-hj
python绘图指南 - 分形与数据可视化 可视化 python 几何学 算法
分形、大自然的分形几何、数据可视化、Python绘图中国传统中的『分形』大自然的分形几何数据可视化本系列采用turtle、matplotlib、numpy这三个Python工具,以分形与计算机图像处理的经典算法为实例,通过程序和图像,来帮助读者一步步掌握Python绘图和数据可视化的方法和技巧,并且让读者感受到“龙枝屈曲竞分形,瑰丽绮错千万状”的分形魅力。本系列共有八章,分别为海岸线有多长,基因与
自动驾驶面临的挑战与应对策略
自动驾驶
尽管自动驾驶技术取得了显著的进展,但在实现全面商业化和广泛应用之前,仍面临着诸多挑战。这些挑战不仅涉及技术层面,还包括法规、社会接受度等多个方面。技术挑战是自动驾驶面临的首要问题。虽然目前的传感器和算法能够在大多数情况下实现车辆的自动驾驶,但在一些复杂的交通场景下,如恶劣天气、道路施工、突发事件等,自动驾驶系统的性能仍然受到很大的限制。例如,在暴雨、大雪等恶劣天气条件下,传感器的精度和可靠性会下降
模拟法练习C++ 1
c++初学者ABC
C++ c++ 开发语言 算法
有错请指出!对于模拟法,百度定义是其实,没有这么麻烦,也就是题目是什么,我们就怎么写,也可以说它是不是算法的算法,最好把代码模块化特点:1.题目简单,代码量很大2.不好找错误3.在比赛中经常考4.代码灵活下面是几道例题1.扑克游戏题目描述三张扑克牌比大小,每个人从扑克牌中抽取三张牌,然后进行比较,规则如下:点数规则:A为最小,K为最大。A记为1点,JQK分别记为11点、12点、13点。比较规则:最
[C++技能提升]类注册
Hunter_pcx
工程技能 人工智能 c++
最近在做AI信息在各个平台流转的框架设计,想要设计一种可以灵活扩展、不改变原有代码的框架,了解到了类注册。具体需求是这样的:AI算法在客户本地电脑和云端都有部署,原先AI在这两个平台下的输出格式并不统一,且每个AI功能都有自己的输出格式,导致两个平台下的AI信息无法共享,带来了计算资源的浪费,管理起来也比较混乱,因此需要一种模式将所有AI输出规范起来。我的解决思路大概就是将所有AI信息都规范输出到
leetCode热门100题——3.最长连续序列
Bin二叉
leetcode 算法 数据结构 java
目录题目描述分析方法:从最小数开始遍历思路代码时间复杂度题目描述给定一个未排序的整数数组nums,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。请你设计并实现时间复杂度为O(n)的算法解决此问题。示例1:输入:nums=[100,4,200,1,3,2]输出:4解释:最长数字连续序列是[1,2,3,4]。它的长度为4。示例2:输入:nums=[0,3,7,2,5,8,4,6,0,1
改进候鸟优化算法之二:基于混沌映射的候鸟优化算法(MBO-CM)
搏博
算法 人工智能 r语言 开发语言 算法 策略模式
基于混沌映射的候鸟优化算法(MigratingBirdsOptimizationbasedonChaoticMapping,MBO-CM)是一种结合了混沌映射与候鸟优化算法(MigratingBirdsOptimization,MBO)的优化方法。一、候鸟优化算法(MBO)简介候鸟优化算法是一种自然启发的元启发式算法,由Duman等人于2011年(也有说法为2012年)提出。该算法模拟候鸟在迁徙过
Nacos负载均衡
平凡人笔记
平凡人笔记 负载均衡 java 运维
常见的负载均衡策略随机、hash、轮询、权重、最小连接数、最快响应速度适用场景1、在短连接中因为连接快速建立销毁因为数据延时容易造成堆积效应,随机、hash、轮询、权重四种方式大致能够保持整体是均衡的,服务端重启也不会影响整体均衡2、最小连接、最快响应速度是有状态的算法,因为数据延时容易造成堆积效应3、长连接,连接会一直保持,断连后需要重新选择一个新的服务节点,当服务重启后,最终连接数会出现不均衡
SQL实现md5加密方法
m0_74824002
面试 学习路线 阿里巴巴 sql 数据库
1.MD5加密概述MD5(MessageDigestAlgorithm5)是一种广泛使用的哈希算法,它将输入的字符串(或数据)转换为固定长度的128位(16字节)哈希值。MD5的主要特点是:不可逆性:MD5是一种单向哈希算法,这意味着你无法从MD5哈希值还原出原始数据。输出固定长度:无论输入数据的长度如何,MD5输出的哈希值始终是32个字符的十六进制数(128位)。碰撞性:虽然MD5很长时间被广泛
2025数学建模美赛B题完整建模思路——管理可持续旅游业
鹿鹿数模
数学建模
2025MCM问题B:管理可持续旅游业以下是我们对该题目的赛题分析,由于完整内容过长,因此在此处放出部分内容,欢迎从文末小卡片处加群获取。赛题分析以下内容包括三个主要部分:(1)题目的中文翻译(2)对题目的整体分析与思路综述(3)对题目要求的逐项详细分析与求解思路。本文的撰写将综合运用多元的数学模型、算法以及机器学习/深度学习的方法,并在必要时给出题外假设与可行的创新性思路,以期为参赛者提供较为系
AcWing算法基础课笔记——高斯消元
SharkWeek.
AcWing 算法 笔记 数论
高斯消元用来求解方程组a11x1+a12x2+⋯+a1nxn=b1a21x1+a22x2+⋯+a2nxn=b2…an1x1+an2x2+⋯+annxn=bna_{11}x_1+a_{12}x_2+\dots+a_{1n}x_n=b_1\\a_{21}x_1+a_{22}x_2+\dots+a_{2n}x_n=b_2\\\dots\\a_{n1}x_1+a_{n2}x_2+\dots+a_{nn}x
算法练习——函数、递归和递推
SharkWeek.
算法练习 算法 递归 深度优先 c++
在此记录一些有关函数、递归和递推的问题。所有题目均来自洛谷的题单能力提升综合题单Part1入门阶段-题单-洛谷|计算机科学教育新生态(luogu.com.cn)(实际上都没有用递推做)[NOIP2001普及组]数的计算题目描述给出正整数nnn,要求按如下方式构造数列:只有一个数字nnn的数列是一个合法的数列。在一个合法的数列的末尾加入一个正整数,但是这个正整数不能超过该数列最后一项的一半,可以得到
C#在软件定义无线电(SDR)开发中的革命性应用——从概念到实践的全面解析
墨夶
C#学习资料2 c# 网络 开发语言
在这个数字化与无线通信飞速发展的时代,软件定义无线电(SoftwareDefinedRadio,SDR)作为一项关键技术,正在改变着我们对传统无线电系统的认知。它不仅允许工程师们以软件的方式实现复杂的信号处理算法,而且还为各种新型无线应用提供了无限可能。然而,要真正驾驭这项技术并非易事,尤其是在选择合适的编程语言时更是如此。今天,我们将聚焦于C#这一强大而灵活的语言,探讨它是如何成为SDR开发的理
GFPGAN - 腾讯开源的图形修复算法修复算法
小众AI
AI开源 开源 算法 人工智能
GFPGAN是腾讯开源的人脸修复算法,它利用预先训练好的面部修复算法,并且封装了各种丰富多样的先验因素进行盲脸(blindface)修复,可以对老照片进行很好的修复。35800Stars5900Forks345Issues11贡献者ApacheLicensePython语言代码:https://github.com/TencentARC/GFPGAN更多AI开源软件:AI开源-小众AI主要功能盲修
二分查找算法
mcharleylei
算法 python
目录1、概述2、代码实现(1)递归实现(2)非递归实现1、概述二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查
Kmeans与KMedoids聚类对比以及python实现
呵呵爱吃菜
kmeans 聚类 python
在机器学习领域,聚类算法是一种常用的无监督学习方法,用于将数据集中的样本划分为若干个簇,使得同一簇内的样本尽可能相似,而不同簇之间的样本尽可能不同。K-Means和K-Medoids是两种经典的聚类算法,它们都基于划分的思想,但在具体实现和应用场景上存在一些差异。一、算法原理1.K-Means:中心点选择:K-Means算法通过计算簇内所有样本的均值来确定中心点(centroid)。距离度量:通常
算法随笔_21:字符的最短距离
程序趣谈
算法
上一篇:算法随笔_20:区间子数组个数-CSDN博客=====================题目描述如下:给你一个字符串s和一个字符c,且c是s中出现过的字符。返回一个整数数组answer,其中answer.length==s.length且answer[i]是s中从下标i到离它最近的字符c的距离。两个下标i和j之间的距离为abs(i-j),其中abs是绝对值函数。示例1:输入:s="lovel
【优选算法】10----无重复字符的最长子串
Rhzkp
算法 c++ leetcode
---------------------------------------begin---------------------------------------题目解析:看到这一类题目,有没有那种一眼就感觉时要用到滑动窗口的感觉,铁子们?讲解算法原理:方法一:暴力解法:简单粗暴的地毯式搜索暴力解法就像一个没有什么技巧的探险家,直接把所有可能的子串都找出来,然后一个一个检查是不是有重复字符,最
【第四天】零基础入门刷题Python-算法篇-数据结构与算法的介绍-两种常见的递归算法(持续更新)
Long_poem
python 算法 开发语言
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、Python数据结构与算法的详细介绍1.Python中的常用的搜索算法2.两种常见的递归算法3.两种详细的递归算法代码1)斐波那契数列2)阶乘总结前言提示:这里可以添加本文要记录的大概内容:第一天Python数据结构与算法的详细介绍第二天五种常见的排序算法第三天两种常见的搜索算法第四天两种常见的递归算法第五天一种常见的
AlphaFold2的思路总结(十五)
xiaofengzihhh
蛋白质结构预测 深度学习 人工智能 神经网络
2021SC@SDUSC这学期的代码分析工作接近尾声了,我想简单总结一下AlphaFold2的总体思路 具体来看,AlphaFold2主要利用多序列比对(MSA),把蛋白质的结构和生物信息整合到了深度学习算法中。它主要包括两个部分:神经网络EvoFormer和结构模块(Structuremodule)。一、EvoFormer 在EvoFormer中,主要是将图网络(Graphnetworks)
python机器学习
方安乐
python python 机器学习 人工智能
Python机器学习是当前最为热门的机器学习领域之一,其简洁、易用、高效的特点,让越来越多的开发者开始探索其应用。本文将从以下几个方面介绍Python机器学习的基础知识和实践案例,帮助读者更好地理解和应用机器学习技术。前提Python机器学习的应用领域A.图像识别和计算机视觉B.自然语言处理和文本分析C.数据挖掘和推荐系统深度学习A.神经网络的基本原理B.常用的深度学习框架和算法C.深度学习在图像
Python实现itemCF协同过滤推荐算法并计算召回率、准确率、F1分数和覆盖率
计算机软件程序设计
机器学习 python 推荐算法 开发语言
一个完整的Python实现,包括ItemCF协同过滤算法的实现以及召回率、准确率、F1分数和覆盖率等评估指标的计算。将使用Pandas进行数据处理,Scikit-learn进行相似度计算,并编写函数来生成推荐列表和评估模型性能。1.数据准备首先,需要准备数据。假设有一个用户-物品评分矩阵(可以是显式评分或隐式反馈),表示用户对不同酒店的喜好程度。这里可以使用Pandas来处理数据。importpa
情感分析常见算法与模型及实现步骤
计算机软件程序设计
知识科普 算法 情感分析 机器学习
【1】常见算法与模型情感分析(SentimentAnalysis)是一种自然语言处理(NLP)技术,用于识别和提取文本中的主观信息,如情绪、态度和意见。常见的算法和模型包括以下几种:传统机器学习方法朴素贝叶斯(NaiveBayes)基于贝叶斯定理,假设特征之间相互独立。计算简单,适用于大规模数据集。常用于文本分类任务。支持向量机(SVM)通过寻找最优超平面来划分不同的类别。在高维空间中表现良好,适
LeetCode 21. 合并两个有序链表 链表合并 Java实现
Lentr0py
LeetCode 算法题 leetcode 链表 java 算法 数据结构
21.合并两个有序链表21.合并两个有序链表题目来源题目分析题目难度题目标签题目限制解题思路思路:核心算法步骤迭代法代码实现代码解读性能分析复杂度结果测试用例扩展讨论优化写法其他实现总结21.合并两个有序链表题目来源21.合并两个有序链表题目分析将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。题目难度难度:简单题目标签标签:链表题目限制两个链表的节点数目
redis原理
小哲会嘿魔法
redis 数据库 缓存
文章目录redis客户端-认识RESP持久化持久化具体实现1.RDB(RedisDataBase)2.AOF(AppendOnlyFile)事务相关命令主从复制拓扑结构同步过程部分复制实时复制哨兵(Sentinel)哨兵选取主节点流程集群数据分片主节点宕机集群扩容缓存缓存更新缓存预热、缓存穿透、缓存雪崩、缓存击穿分布式锁过期时间校验IdLua脚本watchdog(看门狗)Redlock算法redi
OpenCV实战技术应用
yzx991013
OpenCV基础全集 opencv 人工智能 计算机视觉
10.0角点检测应用技术实现,使用SIFT算法进行特征点检测并绘制。结果:实现过程:解析过程:1.导入模块:importcv2:导入opencv库,用于图像处理操作,包括图像读取、特征提取、图像绘制、匹配等。importnumpyasnp:导入numpy库,用于处理数组数据,在特征描述符的存储和处理中可能会用到。2.函数定义:sift_tz():功能:使用SIFT算法进行特征点检测并绘制。实现:i
「Py」基础语法篇 之 Python缩进规则
何曾参静谧
「Py」Python程序设计 数据库
✨博客主页何曾参静谧的博客(✅关注、点赞、⭐收藏、转发)全部专栏(专栏会有变化,以最新发布为准)「Win」Windows程序设计「IDE」集成开发环境「UG/NX」BlockUI集合「C/C++」C/C++程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「UG/NX」NX定制开发「Py」Python程序设计「Math」探秘数学世界「PK」Pa
基于Python的开源量化交易框架:构建你的量化投资策略
ShAutoit
python 开发语言
量化投资是一种利用数学和统计模型来进行投资决策的方法,它将大量的金融数据与算法相结合,以识别交易机会并执行交易。Python作为一种功能强大且易于使用的编程语言,为开发和实施量化交易策略提供了很好的支持。本文将介绍基于Python的开源量化交易框架,帮助你构建自己的量化投资策略。数据获取和处理在量化投资中,数据是至关重要的。你需要获取和处理市场数据,包括股票价格、指数数据、财务数据等。在Pytho
使用Python实现并行计算算法:效率提升的利器
Echo_Wish
Python进阶 python 算法 开发语言
在处理大规模数据和计算密集型任务时,单线程的处理方式往往显得力不从心。并行计算作为一种提升计算效率的重要手段,能够充分利用多核处理器的优势,加速任务的完成。Python作为一种灵活且功能强大的编程语言,提供了丰富的并行计算工具。本文将详细介绍如何使用Python实现并行计算算法,并通过具体代码示例展示其实现过程。项目概述本项目旨在通过Python实现一个并行计算算法,展示如何利用Python的多线
Kafka 消息存储与销毁机制
AI天才研究院
大数据AI人工智能 计算 kafka wpf 分布式
Kafka消息存储与销毁机制文章目录Kafka消息存储与销毁机制1.背景介绍1.1什么是Kafka1.2Kafka的基本概念解释2.核心概念与联系2.1消息存储机制2.2消息销毁机制2.3分区与副本机制3.核心算法原理具体操作步骤3.1消息存储过程3.2消息消费过程3.3消息销毁过程3.4分区副本同步过程4.数学模型和公式详细讲解举例说明4.1消息存储模型4.2消息销毁模型4.3分区副本同步模型5
Spring4.1新特性——综述
jinnianshilongnian
spring 4.1
目录
Spring4.1新特性——综述
Spring4.1新特性——Spring核心部分及其他
Spring4.1新特性——Spring缓存框架增强
Spring4.1新特性——异步调用和事件机制的异常处理
Spring4.1新特性——数据库集成测试脚本初始化
Spring4.1新特性——Spring MVC增强
Spring4.1新特性——页面自动化测试框架Spring MVC T
Schema与数据类型优化
annan211
数据结构 mysql
目前商城的数据库设计真是一塌糊涂,表堆叠让人不忍直视,无脑的架构师,说了也不听。
在数据库设计之初,就应该仔细揣摩可能会有哪些查询,有没有更复杂的查询,而不是仅仅突出
很表面的业务需求,这样做会让你的数据库性能成倍提高,当然,丑陋的架构师是不会这样去考虑问题的。
选择优化的数据类型
1 更小的通常更好
更小的数据类型通常更快,因为他们占用更少的磁盘、内存和cpu缓存,
第一节 HTML概要学习
chenke
html Web css
第一节 HTML概要学习
1. 什么是HTML
HTML是英文Hyper Text Mark-up Language(超文本标记语言)的缩写,它规定了自己的语法规则,用来表示比“文本”更丰富的意义,比如图片,表格,链接等。浏览器(IE,FireFox等)软件知道HTML语言的语法,可以用来查看HTML文档。目前互联网上的绝大部分网页都是使用HTML编写的。
打开记事本 输入一下内
MyEclipse里部分习惯的更改
Array_06
eclipse
继续补充中----------------------
1.更改自己合适快捷键windows-->prefences-->java-->editor-->Content Assist-->
Activation triggers for java的右侧“.”就可以改变常用的快捷键
选中 Text
近一个月的面试总结
cugfy
面试
本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/46753275
前言
打算换个工作,近一个月面试了不少的公司,下面将一些面试经验和思考分享给大家。另外校招也快要开始了,为在校的学生提供一些经验供参考,希望都能找到满意的工作。 
HTML5一个小迷宫游戏
357029540
html5
通过《HTML5游戏开发》摘抄了一个小迷宫游戏,感觉还不错,可以画画,写字,把摘抄的代码放上来分享下,喜欢的同学可以拿来玩玩!
<html>
<head>
<title>创建运行迷宫</title>
<script type="text/javascript"
10步教你上传githib数据
张亚雄
git
官方的教学还有其他博客里教的都是给懂的人说得,对已我们这样对我大菜鸟只能这么来锻炼,下面先不玩什么深奥的,先暂时用着10步干净利索。等玩顺溜了再用其他的方法。
操作过程(查看本目录下有哪些文件NO.1)ls
(跳转到子目录NO.2)cd+空格+目录
(继续NO.3)ls
(匹配到子目录NO.4)cd+ 目录首写字母+tab键+(首写字母“直到你所用文件根就不再按TAB键了”)
(查看文件
MongoDB常用操作命令大全
adminjun
mongodb 操作命令
成功启动MongoDB后,再打开一个命令行窗口输入mongo,就可以进行数据库的一些操作。输入help可以看到基本操作命令,只是MongoDB没有创建数据库的命令,但有类似的命令 如:如果你想创建一个“myTest”的数据库,先运行use myTest命令,之后就做一些操作(如:db.createCollection('user')),这样就可以创建一个名叫“myTest”的数据库。
一
bat调用jar包并传入多个参数
aijuans
下面的主程序是通过eclipse写的:
1.在Main函数接收bat文件传递的参数(String[] args)
如: String ip =args[0]; String user=args[1]; &nbs
Java中对类的主动引用和被动引用
ayaoxinchao
java 主动引用 对类的引用 被动引用 类初始化
在Java代码中,有些类看上去初始化了,但其实没有。例如定义一定长度某一类型的数组,看上去数组中所有的元素已经被初始化,实际上一个都没有。对于类的初始化,虚拟机规范严格规定了只有对该类进行主动引用时,才会触发。而除此之外的所有引用方式称之为对类的被动引用,不会触发类的初始化。虚拟机规范严格地规定了有且仅有四种情况是对类的主动引用,即必须立即对类进行初始化。四种情况如下:1.遇到ne
导出数据库 提示 outfile disabled
BigBird2012
mysql
在windows控制台下,登陆mysql,备份数据库:
mysql>mysqldump -u root -p test test > D:\test.sql
使用命令 mysqldump 格式如下: mysqldump -u root -p *** DBNAME > E:\\test.sql。
注意:执行该命令的时候不要进入mysql的控制台再使用,这样会报
Javascript 中的 && 和 ||
bijian1013
JavaScript && ||
准备两个对象用于下面的讨论
var alice = {
name: "alice",
toString: function () {
return this.name;
}
}
var smith = {
name: "smith",
[Zookeeper学习笔记之四]Zookeeper Client Library会话重建
bit1129
zookeeper
为了说明问题,先来看个简单的示例代码:
package com.tom.zookeeper.book;
import com.tom.Host;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Wat
【Scala十一】Scala核心五:case模式匹配
bit1129
scala
package spark.examples.scala.grammars.caseclasses
object CaseClass_Test00 {
def simpleMatch(arg: Any) = arg match {
case v: Int => "This is an Int"
case v: (Int, String)
运维的一些面试题
yuxianhua
linux
1、Linux挂载Winodws共享文件夹
mount -t cifs //1.1.1.254/ok /var/tmp/share/ -o username=administrator,password=yourpass
或
mount -t cifs -o username=xxx,password=xxxx //1.1.1.1/a /win
Java lang包-Boolean
BrokenDreams
boolean
Boolean类是Java中基本类型boolean的包装类。这个类比较简单,直接看源代码吧。
public final class Boolean implements java.io.Serializable,
读《研磨设计模式》-代码笔记-命令模式-Command
bylijinnan
java 设计模式
声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* GOF 在《设计模式》一书中阐述命令模式的意图:“将一个请求封装
matlab下GPU编程笔记
cherishLC
matlab
不多说,直接上代码
gpuDevice % 查看系统中的gpu,,其中的DeviceSupported会给出matlab支持的GPU个数。
g=gpuDevice(1); %会清空 GPU 1中的所有数据,,将GPU1 设为当前GPU
reset(g) %也可以清空GPU中数据。
a=1;
a=gpuArray(a); %将a从CPU移到GPU中
onGP
SVN安装过程
crabdave
SVN
SVN安装过程
subversion-1.6.12
./configure --prefix=/usr/local/subversion --with-apxs=/usr/local/apache2/bin/apxs --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr --with-openssl=/
sql 行列转换
daizj
sql 行列转换 行转列 列转行
行转列的思想是通过case when 来实现
列转行的思想是通过union all 来实现
下面具体例子:
假设有张学生成绩表(tb)如下:
Name Subject Result
张三 语文 74
张三 数学 83
张三 物理 93
李四 语文 74
李四 数学 84
李四 物理 94
*/
/*
想变成
姓名 &
MySQL--主从配置
dcj3sjt126com
mysql
linux下的mysql主从配置: 说明:由于MySQL不同版本之间的(二进制日志)binlog格式可能会不一样,因此最好的搭配组合是Master的MySQL版本和Slave的版本相同或者更低, Master的版本肯定不能高于Slave版本。(版本向下兼容)
mysql1 : 192.168.100.1 //master mysq
关于yii 数据库添加新字段之后model类的修改
dcj3sjt126com
Model
rules:
array('新字段','safe','on'=>'search')
1、array('新字段', 'safe')//这个如果是要用户输入的话,要加一下,
2、array('新字段', 'numerical'),//如果是数字的话
3、array('新字段', 'length', 'max'=>100),//如果是文本
1、2、3适当的最少要加一条,新字段才会被
sublime text3 中文乱码解决
dyy_gusi
Sublime Text
sublime text3中文乱码解决
原因:缺少转换为UTF-8的插件
目的:安装ConvertToUTF8插件包
第一步:安装能自动安装插件的插件,百度“Codecs33”,然后按照步骤可以得到以下一段代码:
import urllib.request,os,hashlib; h = 'eb2297e1a458f27d836c04bb0cbaf282' + 'd0e7a30980927
概念了解:CGI,FastCGI,PHP-CGI与PHP-FPM
geeksun
PHP
CGI
CGI全称是“公共网关接口”(Common Gateway Interface),HTTP服务器与你的或其它机器上的程序进行“交谈”的一种工具,其程序须运行在网络服务器上。
CGI可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。如php,perl,tcl等。 FastCGI
FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,只要激活后,不
Git push 报错 "error: failed to push some refs to " 解决
hongtoushizi
git
Git push 报错 "error: failed to push some refs to " .
此问题出现的原因是:由于远程仓库中代码版本与本地不一致冲突导致的。
由于我在第一次git pull --rebase 代码后,准备push的时候,有别人往线上又提交了代码。所以出现此问题。
解决方案:
1: git pull
2:
第四章 Lua模块开发
jinnianshilongnian
nginx lua
在实际开发中,不可能把所有代码写到一个大而全的lua文件中,需要进行分模块开发;而且模块化是高性能Lua应用的关键。使用require第一次导入模块后,所有Nginx 进程全局共享模块的数据和代码,每个Worker进程需要时会得到此模块的一个副本(Copy-On-Write),即模块可以认为是每Worker进程共享而不是每Nginx Server共享;另外注意之前我们使用init_by_lua中初
java.lang.reflect.Proxy
liyonghui160com
1.简介
Proxy 提供用于创建动态代理类和实例的静态方法
(1)动态代理类的属性
代理类是公共的、最终的,而不是抽象的
未指定代理类的非限定名称。但是,以字符串 "$Proxy" 开头的类名空间应该为代理类保留
代理类扩展 java.lang.reflect.Proxy
代理类会按同一顺序准确地实现其创建时指定的接口
Java中getResourceAsStream的用法
pda158
java
1.Java中的getResourceAsStream有以下几种: 1. Class.getResourceAsStream(String path) : path 不以’/'开头时默认是从此类所在的包下取资源,以’/'开头则是从ClassPath根下获取。其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。 2. Class.getClassLoader.get
spring 包官方下载地址(非maven)
sinnk
spring
SPRING官方网站改版后,建议都是通过 Maven和Gradle下载,对不使用Maven和Gradle开发项目的,下载就非常麻烦,下给出Spring Framework jar官方直接下载路径:
http://repo.springsource.org/libs-release-local/org/springframework/spring/
s
Oracle学习笔记(7) 开发PLSQL子程序和包
vipbooks
oracle sql 编程
哈哈,清明节放假回去了一下,真是太好了,回家的感觉真好啊!现在又开始出差之旅了,又好久没有来了,今天继续Oracle的学习!
这是第七章的学习笔记,学习完第六章的动态SQL之后,开始要学习子程序和包的使用了……,希望大家能多给俺一些支持啊!
编程时使用的工具是PLSQL