群智能算法——烟花算法(Fireworks Algorithm)[附matlab]

目录

一、算法背景及介绍

二、标准烟花算法实现

三、算法的特点

四、烟花算法的优化策略


北大计算智能实验室(算法代码)

Computational Intelligence Laboratory, Peking University (pku.edu.cn)

烟花算法官方优化代码

Developments | CIL (pku.edu.cn)


算法背景及介绍

群智能算法主要分为两大类,仿生和非仿生。前者包括蚁群优化(ACO)、粒子群优化(PSO)、鱼群搜索(FSS),萤火虫算法,蝙蝠算法,人工蜜蜂算法(ABC),细菌觅食优化国家(BFO),等等。非仿生算法包括烟花算法(FWA)、水滴算法、脑风暴优化(BSO)和磁性优化算法,等等。

受到烟花在夜空中爆炸产生火花并照亮周围区域这一自然现象的启发,北大教授谭营在2010年提出了烟花算法(Fireworks Algorithm,FWA),其主要思想是通过交互传递信息(直接或间接地)使群体对环境的适应性逐代变得越来越好,从而求得全局最优解或接近最优解的近似解。

FWA以类似烟花爆炸的方式在待求问题的解空间中搜索最优解,每一个烟花或火花都对应一个解。算法主要由资源分配(计算每一个烟花的爆炸半径和产生火花数)、爆炸行为(计算火花位置)和选择策略(选择下一代烟花)三部分构成。标准烟花流程图如下:

分成三部分:

1、 在可行解空间中随机产生一定数量的烟花,每个烟花代表解空间中的一个可行解。

2、根据优化目标函数计算每个烟花的适应度值,并据此确定烟花质量的好坏,以在不同爆炸半径下产生不同数量的火花。在烟花算法中,作者使用了两种形式的火花,分别是爆炸火花和高斯变异火花。其中爆炸火花主要负责对烟花邻近区域的搜索,适应度值好(图左)的烟花在较小的邻近区域内产生较多的火花,反之,适应度值差(图右)的烟花在较大的邻近区域内产生较少的火花。相对于爆炸火花,高斯火花的引入增强了种群的多样性。

3、判定是否满足终止条件。如果满足则停止搜索,否则在爆炸火花、高斯变异火花和烟花中选择一定数量的个体作为烟花进入下一代的迭代。

标准烟花算法实现

链接:fwas.zip
提取码:4sqa 

链接:matlab_fwa.zip
提取码:m5g7 
(代码保存在百度网盘里了,可自行提取,永久有效) 

*  第一个是简化后的代码,第二个是官方源码 ,本文是依照简化后的代码进行讲解的

伪代码实现

1:     随机选择N个地点放置烟花
2:     while 不满足终端条件 do
3:         分别在N个地点发射N个烟花:
4:     for 所有烟花  x i do
5:         计算火花数 Si
6:         计算火花的振幅 Ai
7:     end for
        //mˆ 是由高斯突变产生的火花数
8:     for k = 1 → ˆ m do
9:         随机选择一个烟花 xi,并产生一个火花
10:   end for
11:   根据选择策略选择最佳的火花和其他火花
12: end while

 代码实现

1、主函数初始化定义

%_SET_PARAMETERS___________________________________________________________
% Genereal parameters -----------------------------------------------------
params.dim              = 30;        % 维度
params.seednum          = 5;         %初始种子或者烟花的数量 
params.sonnum           = 50;        %每一次爆炸的火花数
params.maxEva	        = 20000;    %算法最大评估次数
params.modStep          = 100;
params.maxEva_mod100    = params.maxEva/params.modStep;%最大迭代次数
params.gaussianNum		= 5;          %高斯常数                                    

 2、函数设置和参数设置

由于对算法进行不同的函数测试,故设置,如下两式配合调用functionid1

for functionid = 1  %函数1 

params.fun_name = ['functionlib' num2str(functionid)];

 划重点:params.fun_name之后还会调用

获取函数特定参数,存储在函数util_getFunctionParams

params  = util_getFunctionParams(params);

 util_getFunctionParams函数如下,其中Bound表示边界,Init表示初始值,shift_value表示搜索半径,shift表示移动程度:

function [ params ] = util_getFunctionParams( params )

     if (strcmp(params.fun_name, 'fun_ackley'))
        fprintf('Ackley function');
        params.lowerBound   = -100;        
        params.upperBound   =  100;  
        params.lowerInit    =  80;          
        params.upperInit    =  100;
        params.optimum      =   0;
     end

     %-------------------------------------------
     if (strcmp(params.fun_name, 'fun_sphere'))
        fprintf('Sphere function');
        params.lowerBound   = -100;        
        params.upperBound   =  100;      
        params.lowerInit    =  80;          
        params.upperInit    =  100;
        params.optimum      =   0;
     end
    %% Function Lib----------------------------------------------------------

     if (strcmp(params.fun_name, 'functionlib1'))
        fprintf('Sphere/Parabola Function');
        params.lowerBound   = -100;        
        params.upperBound   =  100;      
        params.lowerInit    =  50;          
        params.upperInit    =  100;
        params.optimum      =  0;
     end
     
     global shift;
     global shift_value;
     if shift ==0
         shift_value = 0;
     elseif shift==1
         shift_value = 0.05 * (params.upperBound - params.lowerBound)/2;
     elseif shift==2
         shift_value = 0.1 * (params.upperBound - params.lowerBound)/2;
     elseif shift==3
         shift_value = 0.2 * (params.upperBound - params.lowerBound)/2;
     elseif shift==4
         shift_value = 0.3 * (params.upperBound - params.lowerBound)/2;
     elseif shift==5
         shift_value = 0.5 * (params.upperBound - params.lowerBound)/2;
     elseif shift==6
         shift_value = 0.7 * (params.upperBound - params.lowerBound)/2;
     end
     fprintf('. Bounds: [%1.2f, %1.2f], opt: %1.2f;  %i fireworks search in %i dimensions, shiftation is %.6f', params.lowerBound, params.upperBound, params.optimum, params.seednum, params.dim,shift_value);

end

 opt_FWA函数如下(函数核心):

爆炸强度

在爆炸强度中,即火花的数量确定如下:

其中Si为每个个体或烟花的火花数,m为火花总数的常数,Ymax表示N中最差个体的适应度值。函数f (xi)表示对单个xi的适应度,而最后一个参数 ε 用于防止分母变为零。

 sonsnum_cal函数代码如下

function sonsnum_array = sonsnum_cal(fitness_array, params)
%计算烟花总数,并控制在一个范围
global Max_Sparks_Num;
global Min_Sparks_Num;
global Coef_Spark_Num;

fitness_max = max(fitness_array); 
fitness_sub_max = abs(fitness_max - fitness_array);
fitness_sub_max_sum = sum(fitness_sub_max);

sonsnum_array = zeros(1, params.seednum);

for i = 1 : params.seednum

    sonnum_temp = (fitness_sub_max(i) + eps) / (fitness_sub_max_sum + eps);
    sonnum_temp = round( sonnum_temp * Coef_Spark_Num);

    if sonnum_temp > Max_Sparks_Num
        sonnum_temp = Max_Sparks_Num;
    elseif sonnum_temp < Min_Sparks_Num
            sonnum_temp = Min_Sparks_Num;
    end
	
    sonsnum_array(i) = sonnum_temp; 
end

火花数量的限制如下,其中a,b是常数,round是四舍五入函数。

total_fiteval_times = 0;
Coef_Explosion_Amplitude = 40;%%文献中的A爆炸幅度
Max_Sparks_Num = 40;%%文献中的a
Min_Sparks_Num = 2;%%文献中的b
Coef_Spark_Num = 50;%%文献中的m 

爆炸幅度

爆炸幅度的定义如下:

scope_cal函数代码如下:

function scope_array = scope_cal(fitness_array, params)

global Coef_Explosion_Amplitude;

fitness_best = min(fitness_array);
fitness_sub_best = abs(fitness_best - fitness_array);
fitness_sub_best_sum = sum(fitness_sub_best);
scope_array = zeros(params.seednum);

for i=1:params.seednum
    scope_array(i) = Coef_Explosion_Amplitude * (fitness_sub_best(i) + eps) / (fitness_sub_best_sum + eps);  
end

 位移操作

位移操作是在烟花的每个维度上进行位移,可以定义为

 这里 U(−Ai,Ai) 表示振幅 Ai 间隔内的均匀随机数。

映射规则

映射规则确保所有的个体都保持在可行的空间中,如下:

 其中 ,表示任何越界的火花的位置,UBLB分别表示火花位置的最大边界和最小边界。

sons_generate 函数代码如下:

function [sons_matrix, sons_fitness_array, fitness_best_array] = sons_generate(sonsnum_array, scope_array, seeds_matrix, params,fitness_best_array)
global total_fiteval_times;
global evaTime;

fiteval_time = sum(sonsnum_array);
total_fiteval_times = total_fiteval_times + fiteval_time;

sons_matrix = zeros(fiteval_time, params.dim);
sons_fitness_array = zeros(1, fiteval_time);    
sons_index = 1; 

for i = 1 : params.seednum %烟花数量
    for j = 1 : sonsnum_array(i) %火花大小
	
        seed_position = seeds_matrix(i,:);
        
        allowed_dim_array = ones(1,params.dim);
        dimens_select = ceil(rand*params.dim); %取整 select dimens_select
		
        offset = (rand*2-1) * scope_array(i); %计算位移
        
        for k = 1 : dimens_select
            rand_dimen = ceil(rand*params.dim);
			
            while allowed_dim_array(rand_dimen)==0  
                rand_dimen = ceil(rand*params.dim);
            end
            allowed_dim_array(rand_dimen)=0;
			
            seed_position(rand_dimen) = seed_position(rand_dimen) + offset;%位移公式
            
            if seed_position(rand_dimen) > params.upperBound || seed_position(rand_dimen) < params.lowerBound
			% 映射到超出界限的火花的搜索范围
                span = params.upperBound - params.lowerBound;
                seed_position(rand_dimen) = params.lowerBound + rem(abs(seed_position(rand_dimen)), span);
            end
        end  
        sons_matrix(sons_index,:) = seed_position;
        sons_index = sons_index + 1;
    end
end

for i = 1 : fiteval_time
    sons_fitness_array(i) = feval(params.fun_name, sons_matrix(i,:));
	 if(sons_fitness_array(i)<fitness_best_array(evaTime))
		fitness_best_array(evaTime+1) = sons_fitness_array(i);
	 else
		fitness_best_array(evaTime+1) = fitness_best_array(evaTime);
	 end
	 evaTime = evaTime + 1;
end

 选择策略

距离公式(欧式距离):

概率公式: 

下面附上opt_FWA函数代码: 

function [fitness_best_array_return, time_return] = opt_FWA(params)
tic %计算时间开始
global total_fiteval_times;
global Coef_Explosion_Amplitude;
global Max_Sparks_Num;
global Min_Sparks_Num;
global Coef_Spark_Num;

total_fiteval_times = 0;
Coef_Explosion_Amplitude = 40;%%文献中的A爆炸幅度
Max_Sparks_Num = 40;%%文献中的a
Min_Sparks_Num = 2;%%文献中的b
Coef_Spark_Num = 50;%%文献中的m


global evaTime; %评估次数
evaTime = 0;
SeedsMatrix         = zeros(params.seednum, params.dim); %个体运动后的位置     
fitness_best_array     = zeros(1,params.maxEva); % 存储最佳适应度

% initialization 种子进行初始化,随机生成种子在范围值内
for i = 1 : params.seednum
    SeedsMatrix(i,:) = repmat(params.lowerInit, 1, params.dim) + rand(1, params.dim).* repmat(params.upperInit - params.lowerInit, 1, params.dim);
end

% computing the fitness of each seeds计算每一个种子烟花的适应度
SeedsFitness = zeros(1,params.seednum);

SeedsFitness(1)=feval(params.fun_name,SeedsMatrix(1,:));
evaTime = evaTime + 1;
fitness_best_array(evaTime) = SeedsFitness(1);
%计算第一代种子的最好适应度
%进行循环到5个种子
for i=2:params.seednum
     SeedsFitness(i)=feval(params.fun_name,SeedsMatrix(i,:));
     if(SeedsFitness(i)<fitness_best_array(evaTime))
        fitness_best_array(evaTime+1) = SeedsFitness(i);
     else
        fitness_best_array(evaTime+1) = fitness_best_array(evaTime);
     end
     evaTime = evaTime + 1;
end

%以上是第一代

% iteration by iteration  开始迭代
while evaTime < params.maxEva  %评估次数
    % 计算每一个烟花爆炸出来的火花数量
    sonsnum_array = sonsnum_cal(SeedsFitness,params);
    % 计算每一个烟花的爆炸范围
    scope_array = scope_cal(SeedsFitness,params); 
    % 计算爆炸火花和子代火花的适应度,以及最优适应度
    [SonsMatrix,SonsFitness,fitness_best_array] = sons_generate(sonsnum_array,scope_array,SeedsMatrix,params,fitness_best_array);  
    % 高斯变异,
    [SeedsMatrixGauss,SeedsFitGaussMutation,fitness_best_array] = seedGaussMutation(SeedsMatrix, params,fitness_best_array);  
    % 所有烟花和火花
    AllMatrix     = [SeedsMatrix;SonsMatrix;SeedsMatrixGauss]; 
    % 所有的适应度
    AllFitness    = [SeedsFitness,SonsFitness,SeedsFitGaussMutation];    
    % 选择下一代烟花
    [SeedsMatrix,SeedsFitnessCurrentIte]=selectNextIterationOnEntropy(AllMatrix,AllFitness,params);
    %把结果存到下一代中
    SeedsFitness=SeedsFitnessCurrentIte;    
end

time_return = toc; %计算时间结束
fprintf(' \n Best fitness for FWA: %.6f  ... runtime: %g', fitness_best_array(params.maxEva), time_return);
fitness_best_array_return = fitness_best_array(1,params.maxEva_mod100);
for i = 1 :params.maxEva_mod100
    fitness_best_array_return(i) = fitness_best_array(i*params.modStep);%最优适应度返回值
end

附上主函数代码: 

%% Function setting and parametes setting 函数设置和参数设置

for functionid = 1  %函数1 
     params.fun_name = ['functionlib' num2str(functionid)];
     %num2str[]就是把矩阵中的数按照行展开成字符串,当为数值时则为数值

    % 获取函数特定参数
    params              = util_getFunctionParams(params);
    folder_filename = '\';
    folder_function=[folder_filename params.fun_name '_'];
    %%初始化维度
    repetitions = 30;
    fit_fwa_matrix    = zeros(repetitions, params.maxEva_mod100);
    time_fwa_array = zeros(1,repetitions);
    for time_index = 1:repetitions  
        [fit_fwa_matrix(time_index,:),time_fwa_array(time_index)]  = opt_FWA(params);
        %烟花算法主体和返回值
    end

end

算法的特点

基本烟花算法具有如下特点 :随机性、局部性、爆发性、隐并行性、多样性和瞬时性。

2.1 爆发性

在烟花算法的一次迭代开始后,烟花在辐射范围内爆炸,会产生其他的火花。等本次迭代结束后,烟花算法选择火花作为下一代的烟花,恢复了烟花的数目,并为下次迭代的爆发做好准备。每一次迭代,烟花都会爆发,说明烟花算法具有爆发性。

2.2 瞬时性

当一次迭代计算开始后,各个烟花依据适应度值的不同,产生不同的火花个数和爆炸幅度。接着,烟花算法将在爆炸算子和变异算子的作用下产生火花。最后,首先选出最优个体,再依据距离选择其他的个体。这些选择出来的个体将作为下一代爆炸的烟花,其余的火花不再保留。不保留的火花或烟花将消亡,说明烟花算法具有瞬时性。

2.3 简单性

和群体智能算法一样,每个烟花只需要感知自身周围的信息,遵循简单的规则,完成自身的使命。总体看来,烟花算法本身并不复杂,由简单个体组成,说明烟花算法具有简单性。

2.4 局部覆盖性

在烟花算法中,所有的烟花都会在相应的爆炸幅度内产生火花。除非超出可行域,产生的火花都局限在一定的范围内。烟花算法的局部性特点体现了烟花算法强大的局部搜索能力,可以用在算法运算的后期更加精细的搜索最优解。因此,烟花算法具有局部性。

2.5 涌现性

烟花之间通过竞争与协作,群体之间表现出简单个体不具有的高度智能性。烟花之间相互作用,比单个个体的行为要复杂得多,因此烟花算法具有涌现性。

2.6 分布并行性

在烟花算法的每次迭代过程中,各个烟花在不同坐标范围内依次爆炸,即对不同的坐标区间进行一次搜索,在最后会将所有的火花和烟花综合起来,进行下一代烟花的选择。在一次迭代中,算法实质上是并行搜索,表现出烟花算法的分布并行性。

2.7 可适应性

种群多样性是影响群体优化算法性能的关键。群体多样性的保持,可以保证算法跳出局部极值点,从而可以收敛到全局最优点,这正是群体优化算法与一般优化算法的显著区别。群体多样性越大,算法中的个体分布越广,找到最优值的可能越大,同时还不会明显影响算法的收敛能力。因此,种群多样性是烟花算法的一个重要组成部分。烟花算法的多样性主要体现下面三个方面。

2.7.1 火花个数和爆炸幅度的多样性

在爆炸算子的作用下,依据各个烟花的适应度值,其产生不同个数的火花和不同的爆炸幅度。适应度值高的烟花产生更多的火花,爆炸幅度相对较小,而适应度值低的烟花产生更少的火花,爆炸幅度相对较大。因此,保证了火花个数和爆炸幅度的多样性。

2.7.2 位移操作和高斯变异的多样性

烟花算法有两种算子,第一种是爆炸算子,第二种是变异算子。在爆炸算子的位移操作中,对计算出来的幅度范围,随机产生一个位移,将在选中的烟花加上这个随机位移。在变异算子的作用下,选中的烟花需要乘以一个满足高斯分布的随机数。爆炸算子与烟花的适应度值有关,变异算子与烟花本身的坐标值有关。两种算子是本质上不同的,都保证了爆炸的多样性。

2.7.3 烟花的多样性

通过一定的选择机制,保留下来的烟花坐标值各不相同,从而保证了烟花算法的多样性特征。另外,在选择策略中,距离其他火花距离更大的火花更容易被选中,也体现出烟花算法中烟花的多样性特征。

2.8 可扩充性

烟花算法中烟花和火花的数量不确定,可以依据问题的复杂度来确定。烟花和火花的数目可多可少,增加和减少个体都能有效地求解问题,因此烟花算法具有可扩充性。

2.9 适应性

烟花算法求解问题时,不要求问题具有显示表达,只要计算适应度值就能求解问题。同时,烟花算法对问题的要求低,也能求解显示表达的问题。因此烟花算法具有适应性。

烟花算法的优化策略

对FWA的改进工作可以分为两类。一种是基于改进FWA的局限性,另一种是与其他SI算法杂交。

一、近似方法对精英策略加速烟花算法搜索的影响的实证研究。它使用了三种数据采样方法来近似e适应度景观,即最佳适合度抽样方法,接近最佳适合度个体抽样方法的抽样距离,以及随机抽样方法。对于每种近似方法,采用不同的采样方法和采样数进行了一系列的组合评价。对基准函数的实验评价我们认为该精英策略可以有效地提高烟花算法的搜索能力。同时分析和讨论了近似模型的影响岭法,并对烟花算法的加速性能进行了采样数分析。

二、控制勘探开发的FWA,提供了一种新的方法来计算烟花爆炸火花的数量和幅度。通过设计利用传递函数,将火灾的等级数映射到火灾爆炸的范围和火花数的计算规模上。一个参数用于动态控制勘探和利用FWA与迭代的进行。

三、提出了增强烟花算法(EFWA),对FWA进行了全面分析,指出了FWA的5个局限性。提出了克服这些限制的新算子,包括最小爆炸振幅检查策略、新的映射算子、新的推广算子爆炸火花,新的高斯突变算子,和选择算子。

四、提出了一种动态搜索烟花算法(dynFWA)。dynFWA是对最近开发的增强型烟花算法(EFWA)的改进,该算法使用了一个动态爆炸放大器对于核心烟花(CF),即当前最佳位置的烟花。这个动态爆炸振幅取决于CF周围当前局部搜索的质量。主要任务 CF是执行本地搜索,而所有其他烟花的责任是保持全局搜索能力。此外,本章还分析了删除相反的可能, 耗时的EFWA的高斯火花算子。大量的实验评估表明,所提出的dynFWA算法显著提高了EFWA的结果,并减少了m的运行时间超过20%。

五、一种新的算法被称为自适应烟花算法 ,提出了一种自适应方法取代了EFWA中的爆炸振幅算子。爆炸幅度是影响烟花算法性能的关键因素,需要精确控制。最好的烟花和一个受某些条件影响的人的距离被使用爆炸的振幅。分析自适应爆炸幅的性质,得出了自适应爆炸幅是理论上有前途的算子。根据CEC13的28个基准函数的实验结果,其性能得到了显著提高。

六、通过将一种面向概率导向的爆炸机制(POEM)纳入传统的FWA中,提出了一种新的合作烟花算法(简称CoFWA),提高他在蜂群中的烟花之间互动。在CoFWA中,设计了火花产生和烟花选择的诗歌机制,以加强合作能力 ,在CoFWA的个人烟花。实验表明,CoFWA的性能显著优于FWA(即EFWA和dynFWA)和SPSO2011,并表现出竞争性能。

七、烟花算法也适用于与其他EC算法相结合,以产生新的有效的混合算法。给出了FWA与其他SI算法的组合出局重点介绍了混合烟花算法,包括具有微分突变的烟花算法(FWADM)、具有微分演化算子的混合烟花优化算法(F 文化烟花算法(CFWA),以及基于生物地理学的混合优化和烟花算法(BBO FWA)。

八、FWA在多目标问题上的应用。针对油料作物的VRF问题,提出了一种有效的MOFWA算法, 它使用了一个特定问题的策略来生成初始种群,使用帕累托优势的概念来进行个体评价和选择,并结合DE算子来增加t 他共享信息,从而使搜索多样化。MOFWA算法已成功地应用于许多VRF问题,并证明了其有效性和有效性。

  • 8
    点赞
  • 116
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
MATLAB智能算法是指在MATLAB环境下使用智能算法来解决问题的方法。智能算法是一类模拟自然界生物行为或物理现象的算法,常用的智能算法包括蚁优化(ACO)、粒子优化(PSO)、鱼搜索(FSS)、萤火虫算法、蝙蝠算法、人工蜜蜂算法(ABC)、细菌觅食优化(BFO)等\[3\]。这些算法通过模拟生物体的行为,以寻找最优解或近似最优解。在MATLAB中,可以使用这些算法来解决各种实际问题,例如优化问题、机器学习、数据挖掘等。《MATLAB智能算法30个案例分析》是一本介绍MATLAB实现智能算法的书籍,其中提供了30个案例,每个案例都包含理论讲解、案例背景、MATLAB程序实现和扩展阅读等部分\[2\]。这本书可以作为学习和应用MATLAB智能算法的参考书籍,适用于本科毕业设计、研究生项目设计、博士低年级课题设计等\[2\]。 #### 引用[.reference_title] - *1* *2* [《MATLAB智能算法30个案例》:第7章 多种遗传算法的函数优化算法](https://blog.csdn.net/sinat_34897952/article/details/125589983)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [智能算法——烟花算法Fireworks Algorithm)[matlab]](https://blog.csdn.net/qq_63761366/article/details/125739362)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值