算法思路
① 哪位高手能提供一个扑克牌算24点的算法思路
我们来看看“算24点”的游戏规则:一副牌中抽去大小王剩下了52张,其中J、Q、K可以当成是11、12、13,也可以都当成1。任意抽取4张牌,用加、减、乘、除(可加括号)把牌面上的数算成24。每张牌必须用一次且只能用一次。谁先算出来,四张牌就归谁,如果无解就各自收回自己的牌,哪一方把所有的牌都赢到手中,就获胜了。
02
一般情况下,先要看4张牌中是否有2,3,4,6,8,Q ,如果有,考虑用乘法,将剩余的3个数凑成对应数。如果已有两个6,剩下的只要能凑成3,4,5都能算出24,已有两个8,剩下的只要能凑成2,3,4,已有两个Q,剩下的只要能凑成1,2,3都能算出24,比如(9,J,Q,Q)。如果没有2,3,4,6,8,Q,看是否能先把两个数凑成其中之一。
② 算法是解决问题的思路,确定算法以后可以通过什么什么什么或什么来描述。
1、算法就是解决问题的【方法】和【步骤】.
2、算法描述可以有多种表达方法,一般用【自然语言】【流程图】和【伪代码】描述.
3、【伪代码(Pseudocode)】是介于自然语言和计算机程序语言之间的一种算法描述.它也是专业软件开发人员描述算法的一种常用方法.
4、【算法】是程序设计的“灵魂”,世界着名计算机科学家【尼克劳斯沃思(NWirth)】指出:【算法】 + 数据结构=程序.
5、程序设计语言的发展经历了机器语言、汇编语言到【高级语言】的过程.其中计算机可以直接识别的是【机器语言】,它是由【一串由“0”和“1”构成的二进制】代码.
望采纳.
③ GBDT算法
对于AdaBoost,可以将其视为一个将多个弱分类器线性组合后对数据进行预测的算法,该模型可以表示为:
为基函数(即单个弱分类器), 为基函数的参数(即弱分类器中特征的权重向量), 为基函数的系数(即弱分类器在线性组合时的权重), 就是基函数的线性组合。
给定训练数据和损失函数 的条件下,构建最优加法模型 的问题等价于损失函数最小化:
这个公式展现了AdaBoost算法的核心过程。
我们可以利用前向分布算法来求解上一个式子的最优参数。前向分布算法的核心是 从前向后,每一步计算一个基函数及其系数,逐步逼近优化目标函数式 ,就可以简化优化的复杂度。
M-1个基函数的加法模型为:
M个基函数的加法模型:
由上面两式得:
由这个公式和公式(2)得极小化损失函数:
算法思路如下:
1. 初始化
2. 对m=1,2,...,M:
a. 极小化损失函数: 得到参数
b. 更新:
3. 得到加法模型:
这样,前向分布算法将同时求解从m=1到M所有参数 的优化问题化简为逐次求解各个 的优化问题。
Freidman提出了梯度提升算法,算法的核心是利用损失函数的负梯度将当前模型的值作为回归问题提升树算法中的残差的近似值,去拟合一个回归树。
GBDT的思想就是不断去拟合残差,使残差不断减少。用一个通俗的例子来讲假如有个人30岁,我们首先用20岁去拟合,发现损失有10岁,这时我们用6岁去拟合剩下的损失,发现差距还有4岁,第三轮我们用3岁拟合剩下的差距,差距就只有一岁了。如果我们的迭代轮数还没有完,可以继续迭代下面,每一轮迭代,拟合的岁数误差都会减小。(参考 集成学习之Boosting-gbdt )GBDT中每次迭代构造的Cart树都是用前一轮的残差拟合的。
第t轮第i个样本的损失函数的负梯度表示为:
利用 我们可以拟合一颗CART回归树,得到了第t颗回归树,其对应的叶节点区域 其中J为叶子节点个数。
针对每一个叶子节点里的样本,我们求出使损失函数最小的 输出值 :
这样我们就得到了本轮的决策树拟合函数:
从而本轮最终得到的强学习器的表达式如下:
通过损失函数的负梯度来拟合,是一种通用的拟合损失误差的办法。无论是分类问题还是回归问题,我们都可以通过其损失函数的负梯度的拟合,从而用GBDT来解决我们的分类和回归问题。区别仅仅在于损失函数不同导致的负梯度不同而已。
d. 分位数损失:它对应的是分位数回归的损失函数。
输入: 训练样本
迭代次数(基学习器数量): T
损失函数: L
输出: 强学习器H(x)
算法流程
对于二元GBDT,其对数损失函数在之前已经给出:
其中 此时的负梯度误差为:
对于生成的决策树,各个叶子节点的最佳负梯度拟合值为:
由于这个式子不易优化,一般使用近似值代替:
除了负梯度计算和叶子节点的最佳负梯度拟合的线性搜索,二分类GBDT与GBDT回归算法过程相同。
多分类GBDT的损失函数在之前也已经给出过:
样本属于第k类的概率 的表达式为:
结合上面两个式子可以求出第t轮第i个样本对应类别 l 的负梯度误差为:
可以看出,其实这里的误差就是样本i对应类别l的真实概率和t-1轮预测概率的差值。
对于生成的决策树,各个叶子节点的最佳负梯度拟合值为:
由于上式比较难优化,一般用近似值代替:
除了负梯度计算和叶子节点的最佳负梯度拟合的线性搜索,多分类GBDT与二分类GBDT以及GBDT回归算法过程相同。
为了防止GBDT过拟合,需要对其进行正则化。主要有三种方式:
1. 给每棵树的输出结果乘上一个步长(学习率) a 。之前的弱学习器的迭代式改为:
2. 通过子采样比例进行正则化。GBDT每一轮建树时样本从原始训练集中采用无放回随机抽样的方式产生。若采样比例取1,则采用全部样本进行训练。为了防止过拟合,同时又要防止样本拟合偏差较大(欠拟合),要合理取值,常用 [0.5, 0.8]
3. 对弱学习器(CART)进行正则化剪枝:控制树的最大深度、节点最少样本数、最大叶子节点数、节点分支的最小样本数等。
优点 :
缺点 :
由于弱学习器之间存在依赖关系,难以并行训练数据
boosting框架相关参数 :
弱学习器参数 :
GBDT的适用面非常广,几乎可以用于所有回归问题(线性/非线性),也可以用于分类问题。
④ 请教高人 递归算法编写思路技巧
一个子程序(过程或函数)的定义中又直接或间接地调用该子程序本身,称为递归。递归是一种非常有用的程序设计方法。用递归算法编写的程序结构清晰,具有很好的可读性。递归算法的基本思想是:把规模大的、较难解决的问题变成规模较小的、易解决的同一问题。规模较小的问题又变成规模更小的问题,并且小到一定程度可以直接得出它的解,从而得到原来问题的解。
利用递归算法解题,首先要对问题的以下三个方面进行分析:
一、决定问题规模的参数。需要用递归算法解决的问题,其规模通常都是比较大的,在问题中决定规模大小(或问题复杂程度)的量有哪些?把它们找出来。
二、问题的边界条件及边界值。在什么情况下可以直接得出问题的解?这就是问题的边界条件及边界值。
三、解决问题的通式。把规模大的、较难解决的问题变成规模较小、易解决的同一问题,需要通过哪些步骤或等式来实现?这是解决递归问题的难点。把这些步骤或等式确定下来。
把以上三个方面分析好之后,就可以在子程序中定义递归调用。其一般格式为:
if 边界条件 1 成立 then
赋予边界值 1
【 elseif 边界条件 2 成立 then
赋予边界值 2
┇ 】
else
调用解决问题的通式
endif
例 1 : 计算勒让德多项式的值
x 、 n 由键盘输入。
分析: 当 n = 0 或 n = 1 时,多项式的值都可以直接求出来,只是当 n > 1 时,才使问题变得复杂,决定问题复杂程度的参数是 n 。根据题目提供的已知条件,我们也很容易发现,问题的边界条件及边界值有两个,分别是:当 n = 0 时 P n (x) = 1 和当 n = 1 时 P n (x) = x 。解决问题的通式是:
P n (x) = ((2n - 1)P n - 1 (x) - (n - 1)P n - 2 (x)) / n 。
接下来按照上面介绍的一般格式定义递归子程序。
function Pnx(n as integer)
if n = 0 then
Pnx = 1
elseif n = 1 then
Pnx = x
else
Pnx = ((2*n - 1)*Pnx(n - 1) - (n - 1)*Pnx(n - 2)) / n
endif
end function
例 2 : Hanoi 塔问题:传说印度教的主神梵天创造世界时,在印度北部佛教圣地贝拿勒斯圣庙里,安放了一块黄铜板,板上插着三根宝石针,在其中一根宝石针上,自下而上地放着由大到小的 64 个金盘。这就是所谓的梵塔( Hanoi ),如图。梵天要求僧侣们坚持不渝地按下面的规则把 64 个盘子移到另一根针上:
(1) 一次只能移一个盘子;
(2) 盘子只许在三根针上存放;
(3) 永远不许大盘压小盘。
梵天宣称,当把他创造世界之时所安放的 64 个盘子全部移到另一根针上时,世界将在一声霹雳声中毁灭。那时,他的虔诚的信徒都可以升天。
要求设计一个程序输出盘子的移动过程。
分析: 为了使问题更具有普遍性,设共有 n 个金盘,并且将金盘由小到大依次编号为 1 , 2 ,…, n 。要把放在 s(source) 针上的 n 个金盘移到目的针 o(objective) 上,当只有一个金盘,即 n = 1 时,问题是比较简单的,只要将编号为 1 的金盘从 s 针上直接移至 o 针上即可。可定义过程 move(s,1,o) 来实现。只是当 n>1 时,才使问题变得复杂。决定问题规模的参数是金盘的个数 n ;问题的边界条件及边界值是:当 n = 1 时, move(s,1,o) 。
当金盘不止一个时,可以把最上面的 n - 1 个金盘看作一个整体。这样 n 个金盘就分成了两个部分:上面 n - 1 个金盘和最下面的编号为 n 的金盘。移动金盘的问题就可以分成下面三个子问题(三个步骤):
(1) 借助 o 针,将 n - 1 个金盘(依照上述法则)从 s 针移至 i(indirect) 针上;
(2) 将编号为 n 的金盘直接从 s 针移至 o 针上;
(3) 借助 s 针,将 i 针上的 n - 1 个金盘(依照上述法则)移至 o 针上。如图
其中第二步只移动一个金盘,很容易解决。第一、第三步虽然不能直接解决,但我们已经把移动 n 个金盘的问题变成了移动 n - 1 个金盘的问题,问题的规模变小了。如果再把第一、第三步分别分成类似的三个子问题,移动 n - 1 个金盘的问题还可以变成移动 n - 2 个金盘的问题,同样可变成移动 n - 3 ,…, 1 个金盘的问题,从而将整个问题加以解决。
这三个步骤就是解决问题的通式,可以以过程的形式把它们定义下来:
hanoi(n - 1,s,o,i)
move(s,n,o)
hanoi(n - 1,i,s,o)
参考程序如下:
declare sub hanoi(n,s,i,o)
declare sub move(s,n,o)
input "How many disks?",n
s = 1
i = 2
o = 3
call hanoi(n,s,i,o)
end
sub hanoi(n,s,i,o)
rem 递归子程序
if n = 1 then
call move(s,1,o)
else
call hanoi(n - 1,s,o,i)
call move(s,n,o)
call hanoi(n - 1,i,s,o)
endif
end sub
sub move(s,n,o)
print "move disk";n;
print "from";s;"to";o
end sub
⑤ 求一个最优路径算法的思路
同意楼上,最长路径是NPC问题,不存在多项式算法。
证明是简单的:
1、最长无环路问题的判定版本是“给定有向图D和整数k,问D中是否存在长度大于或等于k的无环路”(这一表述对有权图和无权图都有效)。
2、将Hamilton路问题规约到最长无环路问题(的判定版本)是显然的:输入一个n顶点的有向图D,直接问:有向图D中是否存在长度大于等于n-1的无环路?
简言之,对任意n顶点的有向图D,假如能够D中的找到最长无环路P,那么就能立即知道D中是否存在Hamilton路(只需看P的长度是否为n-1即可),从而最长无环路问题是NPC。
小规模就直接DFS吧。大规模的时候DFS剪枝。不过确实不好做呀。
有向无圈图的话可以用dijstra贪心,或者简单用folyed算法就可以了(把最小化变为最大化)。
有圈的话您……或者能缩圈么?可以考虑。总之比较复杂。
⑥ 禁忌搜索算法的主要思路
1、在搜索中,构造一个短期循环记忆表-禁忌表,禁忌表中存放刚刚进行过的 |T|(T称为禁忌表)个邻居的移动,这种移动即解的简单变化。
2、禁忌表中的移动称为禁忌移动。对于进入禁忌表中的移动, 在以后的 |T| 次循环内是禁止的,以避免回到原来的解,从而避免陷入循环。|T| 次循环后禁忌解除。
3、禁忌表是一个循环表,在搜索过程中被循环的修改,使禁忌表始终保持 |T| 个移动。
4、即使引入了禁忌表,禁忌搜索仍可能出现循环。因此,必须给定停止准则以避免出现循环。当迭代内所发现的最好解无法改进或无法离开它时,算法停止。