算法导论

算法导论

1、动态规划

动态规划与递归有些神似,适用场景不同而已。

关于动态规划,《算法导论》上给出好几个例子,第一个就是装配线调度问题,抽象成如下形式:

递归的出口在j=1处,需要求解的则是f[1,n]和f[2,n]。

上式已经是递归的形式。但实际上,若采用传统的递归方法,计算代价会非常的高,因为的值需要重复的被计算次。

下图说明为什么会被重复计算,并且是2的幂指数形式(假设n=3):

从这张图就看的比较清楚了。原因在于,递归每一“层”的结果需要被计算的次数,是上一“层”结果被计算次数的两倍;

例如f[2,j-1]要同时被f[1,j]和f[2,j]使用,这一点直接来自递归式。图中第4层的f[2,1]被计算四次,而其上一层的结果f[1,2]和f[2,2]则分别被计算两次。

坑爹之处在于,这种倍数关系在树中就变成了幂指数关系。

动态规划的思路是:先计算小的子任务,再计算较大的子任务;在计算较大子任务时,所需的小子任务的值已经计算好,这样便能直接拿来用,无需重复计算。

例如这里先计算出f[1,0]和f[2,0]并保存结果;随后计算较大的子任务f[1,1]和f[2,1]时,它们所需要的就是f[1,0]和f[2,0]的值,已经是现成的。

而多数情况下,我们都可以放心大胆的用递归方法。具体来说,若递归每一“层”结果的计算次数是上一“层”的1倍的时候,就可以使用传统递归方法。因为1倍的倍数关系转换为幂指数后,也不可怕。

举个简单的例子。f(i)=f(i-1)+2,递归出口是f(1)=0,那么递归求解f(5)大概是这样的:

以上说完了动态规划和递归的区别。装配线调度的问题,使用动态规划方法,就是“自底向上”的计算:先计算f[1,0]和f[2,0];再逐次向上计算。

《算法导论》还提到了矩阵乘法的问题,简介如下。待计算的问题抽象为:

待求的是m[1,n]。注意,“需要被用到的m[i,j]”铺满了1≤i<j≤n的所有取值。正常情况下采用的递归格式为:

但是这里必须得“自底向上”的计算,即先计算i和j相距较小的m[i,j](否则可能出现计算某个m[i,j]时,所需的m[i,k]或m[k+1,j]尚未被计算的情况);迭代方式变为:

其余没什么好说的。

动态规划适用的场合,有两个主要因素:最优子结构、重叠子问题。

最优子结构是说,一个问题的最优解中包含了其子问题的最优解。在贪心算法中也用到了最优子结构;不同的是,动态规划是“自底向上”的使用,而贪心法则是“自顶向下”的使用:先做(当前看起来是最优的)选择,再求解子问题。

重叠子问题是说,同一个子问题被反复调用。例如在装配线调度上,f[2,1]被反复调用达4次。这时动态规划就能派上用场,它只需计算一次其余均直接查找该值。相反,常见的递归例如f(i)=f(i-1)+2,每个只被调用一次,因此用传统递归方法求解即可,不会造成计算量爆炸。

一个动态规划算法的运行时间,大致等于"子问题的总数量"×"每个子问题面临多少个选择"。例如矩阵乘法问题,子问题数量有(取遍1≤i<j≤n的所有值)个;而每个子问题面临个选择(1≤k<j);所以整体时间复杂度为

使用动态规划的一个前提条件是各子问题是独立的。所谓独立,是指各子问题之间绝不会共享资源,从而一个子问题的解不会干扰到另一个子问题。一个反例是“求解图中最长路径”,如下:

为了求B到C的最长路径,我们试图将其分解为两个子问题:B到D的最长路径、D到C的最长路径,连接两者得到结果。这是动态规划的典型思路,却行不通,因为会造成回路,例如"B→C→D"、"D→A→B→C"。之所以如此,就是因为分解得到的两个子问题不独立,彼此的结果干扰,导致结果不可信。

而“最短路径”就不会出现共享资源的问题,这很明显就不加说明了。因此求解最短路径时,可以采用动态规划方法。

 

2、贪心算法

贪心算法与动态规划同是求解最优化问题,并且思路相通。之所以使用贪心算法,是因为不少场合下用它就足以解决问题,并且比动态规划的代价要低。

贪心算法的套路是:(1)设计原问题的一个递归解;(2)证明在递归的任一步骤下,贪心选择总是最优选择之一;(3)证明通过该贪心选择,所有子问题仅一个非空。

《算法导论》给出的“活动选择问题”。有n个活动,每个活动都有起止时间(这里假设n个活动已按终止时间升序排序)。我们期望在一定时间里安排尽可能多的活动。

这个明显可以用动态规划解决。这里只说用贪心算法如何求解。

 

首先设计递归解:用表示在的时间里的最优安排,并设是在该时间段内可以完成的活动。那么有:

贪心选择很直接:找出当前时间段内可以做、并且结束时间最早的活动

我们需要证明:通过这种选择,一定可以构造出一个最优解;换句话说,某个最优解里一定包含,注意当考察的是任意步骤,因此所有步骤的贪心选择拼到一起就是一个最优解。

假设某个最优解不包含活动,并假设最优解的诸活动中,最早结束的是。那么很显然,也是可行的活动安排,并且与先前最优解的活动数量相等。因此说,一定存在某个最优解,其中包含

再证该贪心选择下,仅有一个子问题非空。递归解的表达式右边含两个子问题,但实际上,因为被筛选出的是最早结束的那个,所以这个子问题必定是空集,所以只需考虑即可。

以上。证明贪心选择的正确性的方法可以推广开来:考察一个最优解,对其做微动,引入贪心选择将其变为一个相似的、更小的最优解。

此外,贪心选择后仅剩余一个子问题,这正是它相对于动态规划的优越性的一方面。后者往往面临两个或者更多的子问题。

至此可以理解“自顶向下采用最优子结构”的含义了:为求解,先挑出,再求解。被考察的子问题是越来越小的,所以称为“自顶向下”。而动态规划里被考察的子问题越来越大。

 

3、红黑树

这是一种保证在最坏情况下,基本操作(查找、插入、删除、找前驱后继等)时间复杂度仍为的二叉查找树。

红黑树的基本性质:(1)每个节点或者红、或者黑,根节点必须黑;(2)红节点的两个子节点都为黑;(3)对任意节点,从它到它所有可达叶子节点的路径上,黑节点数量相等。

正是这些基本性质,保证了红黑树的高度为;又因为它仅是一种特殊的二叉查找树,因此基本操作的时间复杂度为

证明如下:设bh(x)是以x为根的子树的“黑高度”(从x到叶子的路径上黑节点个数,不包括x自身),则该子树至少包含个内节点(由数学归纳法易证);子树的高度记作h,而性质(2)保证了根到叶子的路径上黑节点至少占半数,因此;所以有,即

在插入删除等操作时,红黑性质很容易被破坏。这时就需要“旋转”操作来进一步补救被破坏的红黑平衡。

插入节点的过程,就是在普通二叉查找树的插入后做一步fixup操作,使得新树依旧满足红黑树的基本性质。

FIXUP()中又分为6种情况。如下:

有关这里的说明:

(1)循环体内z的祖父一定存在,因为仅p[z]为红才执行循环,而根节点为黑,所以p[z]不是根,所以z的祖父存在;

(2)红黑性质仅可能在z和p[z]处被破坏。所有可能被破坏的红黑性质有两个:①新插入的z是根(注意此时p[z]是黑色的NULL哨兵),违反"根节点必须黑";②z和p[z]均红,违反"红节点的两个孩子必须黑"。

(3)z指针始终指向红色节点,因此若p[z]为黑就可以退出循环,再处理"根节点为黑"这一条就万事大吉。

"case 1"如下图所示。其中z是p[z]的左孩子或右孩子无所谓,重点是z的父亲p[z]及叔父y都是红色。既然z的祖父是黑的(那儿并未被破坏,所以由红黑性质,p[p[z]]一定是黑),那可以将p[z]和y置黑、将p[p[z]]置红;这种一则"红节点两个孩子均黑"被保证、二则"黑高度"不变;但是p[p[z]]置红可能引起更高层混乱,所以z←p[p[z]]继续迭代。

"case 2"如下图左边所示。它与"case 3"唯一区别在于z是p[z]的左孩子OR右孩子,因此做左旋(并不影响αβγ子树的黑高度等性质),转化为"case 3"再统一处理。注意z指向的节点有变。

"case 3"如上图右边所示。叔父y(δ的根)一定是黑色,因为否则就执行"case 1"去了。这里改变p[z]、p[p[z]]的颜色并做右旋。从图中可以看到αβγδ四棵子树的黑高度均未变;四棵树均有黑根(αβγ处不违反红黑性质且父节点红因此有黑根)所以节点A、C符合红黑性质;z的父亲已是黑色。此前做过说明,p[z]为黑即可退出循环。

删除节点的过程如下。其中y是待删除节点(z的后继或自身)、x是用来顶替y位置的节点。

先统计下可能被违反的红黑性质:①y的红色孩子x成为新根;②x和p[y]均为红;③删除黑色y使得包含y的路径上,黑高度减1。

主要考察情况③,方法是将x视为有一层额外的黑色,即x为"红加黑"(实际是红)或"双重黑"(实际是黑),效果是包含x的路径上黑高度加1(对应"红+黑")或2(对应"双重黑"),以维持原有平衡。

FIXUP()反复迭代,直到两种情况下,此时"额外黑色"的问题被解决:一是x为根,这时毫无压力;二是x指向"红加黑",此时即使考虑额外黑色也只是将通过x的路径的黑高度加1,而x又为红,因此将其置黑即可。

FIXUP()共分8种情况,如下:

"case 1"会被转化为另3种情况,即转换后x的兄弟是黑节点。转换的方法是改变p[x]和w的颜色并对p[x]左旋,如图所示,所有红黑性质不变;注意x的新兄弟是此前w的左孩子,必定为黑(因为此前w是红),因此"case 1"成功化为另3种情况。

"case 2"与后两种情况不同点在于,w的两个孩子均黑;这样的好处是将w置红不违反"红节点两个孩子均黑"的要求,仅是减少了黑高度。因为x"双重黑"而w黑,可以将这层额外黑色沿树往上移,即p[x]变为"红加黑"或"双重黑"。

"case 3"会被转化为"case 4"。通过修改w及其左孩子的颜色并做右旋,可以在不违反红黑性质的情况下变为"case 4"。

"case 4"可以略加改动使得x指向"红加黑"节点,从而简单的将x置黑便可消去额外的黑色,退出循环。具体的修改颜色及旋转见图。可以看到右图的x置黑(不再是"双重黑")后,所有子树、节点的黑高度均不变,且红黑性质得以满足。

 

4、二项堆

先描述二项树:①共有个节点;②树的深度为k;③在深度i处刚好有个节点。如下图所示:

另外可以看作由两个组合而来。

二项堆是由一拨按照度数严格递增(同一度数即k值最多有一棵树)的、最小堆有序的二项树组成。

其中最小堆有序是指二项树里,任意节点的值都大于等于其父节点的值,因此整棵树的最小值是树根。

上图是一个含13个节点的二项堆。注意刚好对应图中的

这样便很好说明,若堆H含有n个节点,则它最多含棵树。因为n的二进制表示有位。

此外在编程实现时,每棵树可以存储“左孩子、右兄弟、父节点”;即存储最左边的孩子,以及紧邻着的右边兄弟,并存储父节点。这是为了适应二项堆的操作,例如UNION时连接一棵树为新的最左孩子,用这种存储方法很容易编程。

合并两个二项堆的操作:

以上是整体逻辑。

首先将两个二项堆简单的合并,注意要按度不递减的顺序,即左边的树的度一定小于等于右边的树的度;这样的堆可能在同一个度上有不止一棵树,后续处理就是为了解决这一问题。

"case 1"时,可以简单的将x右移,不解释。

"case 2"则是连续三棵树的度一样,并且x指向第一棵。为了符合二项堆的性质,应将后两棵树合并起来;不过这里就是简单的将x右移便进入下一轮迭代;将后两棵树合并的操作将在下一轮迭代中,由"case 3"或"case 4"完成。下图便是一个示例。

在最初的MERGE()之后,新堆中同一度数k最多有两棵树;这里形成三棵树,是因为之前有两棵树做了“组合”多形成了一个

"case 3"和"case 4"的场景都是:x与其后继的度相等,且需要组合二者("case 2"也有此相等关系却不该连接);区别在于x和next[x]值的相对大小,使得组合顺序不同。

二项堆还有几个基本操作,都很简单。因此只做列举,不详细说明了:

(1)创建新堆;

(2)插入一个节点(新建一个单节点堆,调用UNION()函数);

(3)寻找最小值节点(只需查找诸子树的根节点即可);

(4)删除最小值节点(删除该节点为根的子树;注意在丢掉树根后变成多棵树,将其组成一个堆;将做UNION即可);

(5)减小节点的值(在二项树中沿着父节点向上遍历,直到不违反"节点值大于等于父节点值"即可);

(6)删除一个节点(通过(5)将该节点赋值为﹣∞,再通过(4)删除即可)。

二项堆最大优势就在于UNION操作是复杂度,否则直接采用二叉堆即可。注意无论是二叉堆还是二项堆,“查找”操作的时间效率都很低。

 

5、最大流算法

含一个源点和一个汇点的有向图,每条边有最大承载容量。要求计算从源点到汇点的最大流量及相应的路径。

首先定义“残留图”、“增广路径”和“割”。

残留图是指,原始图G每条边扣除一定的流量(因为路径f消耗了一部分流量)后得到的图。若初始时图中A点到B点最大承载容量,当前已现的路径path经过边AB并且流量为;则残留图中A点到B点容量记作,并建一条B点到A点的有向边,容量相应记作

增广路径是指残留图中一条从源点出发到达汇点的路径。

的割(S,T)将顶点划分为两个集合,其中。割(S,T)的最大承载容量记作c(S,T);流过它的流量记作f(S,T)。

割的两个性质:

(1)流过任意割的净流量相等。直观上来看,除了源点汇点,其余任意顶点的流入等于流出;真正起作用的仅源点汇点而已,所以具体怎样切割都毫无压力。

(2)任意流的流量小于等于任意割的最大承载容量。不解释。

Ford-Fulkerson方法:初始流设为空;每次迭代从残留图中找出一条增广路径,添加到总流里,重复这个过程直到不存在增广路径;这时的总流就是最大流,其流量就是从源点到汇点的最大流量。

算法的证明如下:

①f是图G的一个最大流;

②残留图不包含增广路径;

③对图G的某个割,有

我们试图证明即可。

不解释;

,构造这样一个割:S为残留图中源点可达的顶点集合、T为V-S;②保证了T不为空集且汇点在T中。此时,对都有c(s,t)=f(s,t)(否则中存在s到t的通路,t应当属于S集合,矛盾)。因此对这个割有

不解释。

这样,由便证明了Ford-Fulkerson方法的正确性。

Ford-Fulkerson方法在编程实现时,主要问题在于,如何从残留图中找出源点到汇点的一条路径。采用递归实现,简要说明一下:

(1)该函数如何处理下一级别的递归。如下:

(2)递归出口,若当前顶点的某个直达点就是汇点,那就是递归出口了。

狗血的是,这个递归可能出现死循环。

如图,源点是node-0、汇点是node-5。源点可直达顶点2,因此询问顶点2"是否能到达汇点";顶点2再去询问顶点4。顶点4自然也是询问自己能直达的顶点,因此它会向2发出同样的询问,这样便在node-2和node-4间形成死锁。

解决办法也很简单,阻止节点往回试探。例如这里不允许节点4回头询问节点2,因为这个询问不可能有结果,若节点2知道,它就不会来问你了。

需要提及的是,直接实现的Ford-Fulkerson方法可能是低效的。例如下图中极端情况下可能会迭代太多次。

改进的出发点就在于,每次都寻找一个很牛X的增广路径(流量大、步数少等),以避免极端情况下迭代次数过多的情况。其中一个具体实现为Edmonds-Karp算法,它采用广度优先搜索来寻找源点到汇点的增广路径,时间复杂度为

 

最后,最大流方法可以用来寻找“最大二分匹配”。将二分图左侧虚构一个源点并与左侧诸点连接(有向边),右侧虚构一个汇点并与右侧诸点连接,这样便构成一个有向图。找出该有向图的最大流,则最大二分匹配立即可得。

转载于:https://www.cnblogs.com/sunshine1991/archive/2013/05/01/3053721.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在有关算法的书中,有一些叙述非常严谨,但不够全面;另一些涉及了大量的题材,但又缺乏严谨性。本书将严谨性和全面性融为一体,深入讨论各类算法,并着力使这些算法的设计和分析能为各个层次的读者接受。全书各章自成体系,可以作为独立的学习单元;算法以英语和伪代码的形式描述,具备初步程序设计经验的人就能看懂;说明和解释力求浅显易懂,不失深度和数学严谨性。 --------------------------------------------------------------- 目录 Introduction to Algorithms, Third Edition 出版者的话 译者序 前言 第一部分 基础知识 第1章 算法在计算中的作用  1.1 算法  1.2 作为一种技术的算法  思考题  本章注记 第2章 算法基础  2.1 插入排序  2.2 分析算法  2.3 设计算法   2.3.1 分治法   2.3.2 分析分治算法  思考题  本章注记 第3章 函数的增长  3.1 渐近记号  3.2 标准记号与常用函数  思考题  本章注记 第4章 分治策略  4.1 最大子数组问题  4.2 矩阵乘法的Strassen算法  4.3 用代入法求解递归式  4.4 用递归树方法求解递归式  4.5 用主方法求解递归式  4.6 证明主定理   4.6.1 对b的幂证明主定理   4.6.2 向下取整和向上取整  思考题  本章注记 第5章 概率分析和随机算法  5.1 雇用问题  5.2 指示器随机变量  5.3 随机算法  ?5.4 概率分析和指示器随机变量的进一步使用   5.4.1 生日悖论   5.4.2 球与箱子   5.4.3 特征序列   5.4.4 在线雇用问题  思考题  本章注记 第二部分 排序和顺序统计量 第6章 堆排序  6.1 堆  6.2 维护堆的性质  6.3 建堆  6.4 堆排序算法  6.5 优先队列  思考题  本章注记 第7章 快速排序  7.1 快速排序的描述  7.2 快速排序的性能  7.3 快速排序的随机化版本  7.4 快速排序分析   7.4.1 最坏情况分析   7.4.2 期望运行时间  思考题  本章注记 第8章 线性时间排序  8.1 排序算法的下界  8.2 计数排序  8.3 基数排序  8.4 桶排序  思考题  本章注记 第9章 中位数和顺序统计量  9.1 最小值和最大值  9.2 期望为线性时间的选择算法  9.3 最坏情况为线性时间的选择算法  思考题  本章注记 第三部分 数据结构 第10章 基本数据结构  10.1 栈和队列  10.2 链表  10.3 指针和对象的实现  10.4 有根树的表示  思考题  本章注记 第11章 散列表  11.1 直接寻址表  11.2 散列表  11.3 散列函数   11.3.1 除法散列法   11.3.2 乘法散列法   11.3.3 全域散列法  11.4 开放寻址法  11.5 完全散列  思考题  本章注记 第12章 二叉搜索树  12.1 什么是二叉搜索树  12.2 查询二叉搜索树  12.3 插入和删除  12.4 随机构建二叉搜索树  思考题  本章注记 第13章 红黑树  13.1 红黑树的性质  13.2 旋转  13.3 插入  13.4 删除  思考题  本章注记 第14章 数据结构的扩张  14.1 动态顺序统计  14.2 如何扩张数据结构  14.3 区间树  思考题  本章注记 第四部分 高级设计和分析技术 第15章 动态规划  15.1 钢条切割  15.2 矩阵链乘法  15.3 动态规划原理  15.4 最长公共子序列  15.5 最优二叉搜索树  思考题  本章注记 第16章 贪心算法  16.1 活动选择问题  16.2 贪心算法原理  16.3 赫夫曼编码  16.4 拟阵和贪心算法  16.5 用拟阵求解任务调度问题  思考题  本章注记 第17章 摊还分析  17.1 聚合分析  17.2 核算法  17.3 势能法  17.4 动态表   17.4.1 表扩张   17.4.2 表扩张和收缩  思考题  本章注记 第五部分 高级数据结构 第18章 B树  18.1 B树的定义  18.2 B树上的基本操作  18.3 从B树中删除关键字  思考题  本章注记 第19章 斐波那契堆  19.1 斐波那契堆结构  19.2 可合并堆操作  19.3 关键字减值和删除一个结点  19.4 最大度数的界  思考题  本章注记 第20章 van Emde Boas树  20.1 基本方法  20.2 递归结构   20.2.1 原型van Emde Boas结构   20.2.2 原型van Emde Boas结构上的操作  20.3 van Emde Boas树及其操作   20.3.1 van Emde Boas树   20.3.2 van Emde Boas树的操作  思考题  本章注记 第21章 用于不相交集合的数据结构  21.1 不相交集合的操作  21.2 不相交集合的链表表示  21.3 不相交集合森林  *21.4 带路径压缩的按秩合并的分析  思考题  本章注记 第六部分 图算法 第22章 基本的图算法  22.1 图的表示  22.2 广度优先搜索  22.3 深度优先搜索  22.4 拓扑排序  22.5 强连通分量  思考题  本章注记 第23章 最小生成树  23.1 最小生成树的形成  23.2 Kruskal算法和Prim算法  思考题  本章注记 第24章 单源最短路径  24.1 Bellman?Ford算法  24.2 有向无环图中的单源最短路径问题  24.3 Dijkstra算法  24.4 差分约束和最短路径  24.5 最短路径性质的证明  思考题  本章注记 第25章 所有结点对的最短路径问题  25.1 最短路径和矩阵乘法  25.2 Floyd?Warshall算法  25.3 用于稀疏图的Johnson算法  思考题  本章注记 第26章 最大流  26.1 流网络  26.2 Ford\Fulkerson方法  26.3 最大二分匹配  26.4 推送重贴标签算法  26.5 前置重贴标签算法  思考题  本章注记 第七部分 算法问题选编 第27章 多线程算法  27.1 动态多线程基础  27.2 多线程矩阵乘法  27.3 多线程归并排序  思考题  本章注记 第28章 矩阵运算  28.1 求解线性方程组  28.2 矩阵求逆  28.3 对称正定矩阵和最小二乘逼近  思考题  本章注记 第29章 线性规划  29.1 标准型和松弛型  29.2 将问题表达为线性规划  29.3 单纯形算法  29.4 对偶性  29.5 初始基本可行解  思考题  本章注记 第30章 多项式与快速傅里叶变换  30.1 多项式的表示  30.2 DFT与FFT  30.3 高效FFT实现  思考题  本章注记 第31章 数论算法  31.1 基础数论概念  31.2 最大公约数  31.3 模运算  31.4 求解模线性方程  31.5 中国余数定理  31.6 元素的幂  31.7 RSA公钥加密系统  31.8 素数的测试  31.9 整数的因子分解  思考题  本章注记 第32章 字符串匹配  32.1 朴素字符串匹配算法  32.2 Rabin\Karp算法  32.3 利用有限自动机进行字符串匹配  32.4 Knuth?Morris?Pratt算法  思考题  本章注记 第33章 计算几何学  33.1 线段的性质  33.2 确定任意一对线段是否相交  33.3 寻找凸包  33.4 寻找最近点对  思考题  本章注记 第34章 NP完全性  34.1 多项式时间  34.2 多项式时间的验证  34.3 NP完全性与可归约性  34.4 NP完全性的证明  34.5 NP完全问题   34.5.1 团问题   34.5.2 顶点覆盖问题   34.5.3 哈密顿回路问题   34.5.4 旅行商问题   34.5.5 子集和问题  思考题  本章注记 第35章 近似算法  35.1 顶点覆盖问题  35.2 旅行商问题  35.2.1 满足三角不等式的旅行商问题  35.2.2 一般旅行商问题  35.3 集合覆盖问题  35.4 随机化和线性规划  35.5 子集和问题  思考题  本章注记 第八部分 附录:数学基础知识 附录A 求和  A.1 求和公式及其性质  A.2 确定求和时间的界  思考题  附录注记 附录B 集合等离散数学内容  B.1 集合  B.2 关系  B.3 函数  B.4 图  B.5 树   B.5.1 自由树   B.5.2 有根树和有序树   B.5.3 二叉树和位置树  思考题  附录注记 附录C 计数与概率  C.1 计数  C.2 概率 C.3 离散随机变量  C.4 几何分布与二项分布  *C.5 二项分布的尾部  思考题  附录注记 附录D 矩阵  D.1 矩阵与矩阵运算  D.2 矩阵基本性质  思考题  附录注记

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值