Python实现VRP常见求解算法——蚁群算法(ACO)

蚁群算法解决TSP(旅行商)问题 文章目录一、前言蚁群算法的基本原理:其中的基本过程二、状态问题1.城市被选择的概率由距离和信息素浓度共同决定2.信息素更新三、整体实现 一、前言 蚁群算法(Ant Colony Optimization,ACO)是一种模拟自然界中蚂蚁觅食行为的优化算法。在蚁群算法中,蚂蚁寻找食物的方式被模拟为一种通过信息素通信来协作搜索解空间的算法。 蚁群算法要求考虑到多个蚂蚁之间相互交流信息的影响,因此也称作反向分布式系统中的元启发式,并已经成功用于旅行商问题(TSP)、车辆路径规划问题(VRP)等优化领域。它利用蚁群 阅读详情

基于python语言,实现经典蚁群算法(ACO)对车辆路径规划问题(CVRP)进行求解。

优质资源

1. 适用场景

  • 求解CVRP
  • 车辆类型单一
  • 车辆容量不小于需求节点最大需求
  • 单一车辆基地

2. 求解效果

(1)收敛曲线
在这里插入图片描述

(2)车辆路径
在这里插入图片描述

3. 问题分析

CVRP问题的解为一组满足需求节点需求的多个车辆的路径集合。假设某物理网络中共有10个顾客节点,编号为1~10,一个车辆基地,编号为0,在满足车辆容量约束与顾客节点需求约束的条件下,此问题的一个可行解可表示为:[0-1-2-0,0-3-4-5-0,0-6-7-8-0,0-9-10-0],即需要4个车辆来提供服务,车辆的行驶路线分别为0-1-2-0,0-3-4-5-0,0-6-7-8-0,0-9-10-0。由于车辆的容量固定,基地固定,因此可以将上述问题的解先表示为[1-2-3-4-5-6-7-8-9-10]的有序序列,然后根据车辆的容量约束,对序列进行切割得到若干车辆的行驶路线。因此可以将CVRP问题转换为TSP问题进行求解,得到TSP问题的优化解后再考虑车辆容量约束进行路径切割,得到CVRP问题的解。这样的处理方式可能会影响CVRP问题解的质量,但简化了问题的求解难度。

4. 数据格式

以xlsx文件储存网络数据,其中第一行为标题栏,第二行存放车辆基地数据。在程序中车辆基地seq_no编号为-1,需求节点seq_id从0开始编号。可参考github主页相关文件。

5. 分步实现

(1)数据结构
为便于数据处理,定义Sol()类,Node()类,Model()类,其属性如下表:

  • Sol()类,表示一个可行解
属性描述
nodes_seq需求节点seq_no有序排列集合,对应TSP的解
obj优化目标值
routes车辆路径集合,对应CVRP的解
  • Node()类,表示一个网络节点
属性描述
id物理节点id,可选
name物理节点名称,可选
seq_no物理节点映射id,基地节点为-1,需求节点从0编号
x_coord物理节点x坐标
y_coord物理节点y坐标
demand物理节点需求
  • Model()类,存储算法参数
属性描述
best_sol全局最优解,值类型为Sol()
node_list物理节点集合,值类型为Node()
sol_list可行解集合,值类型为Sol()
node_seq_no_list物理节点映射id集合
depot车辆基地,值类型为Node()
number_of_nodes需求节点数量
opt_type优化目标类型,0:最小车辆数,1:最小行驶距离
vehicle_cap车辆容量
distance网络弧距离
popsize蚁群规模
alpha信息启发式因子
beta期望启发式因子
Q信息素总量
rho信息素挥发系数
tau网络弧信息素
(2)文件读取
def readXlsxFile(filepath,model):
    node_seq_no = -1
    df = pd.read_excel(filepath)
    for i in range(df.shape[0]):
        node=Node()
        node.id=node_seq_no
        node.seq_no=node_seq_no
        node.x_coord= df['x_coord'][i]
        node.y_coord= df['y_coord'][i]
        node.demand=df['demand'][i]
        if df['demand'][i] == 0:
            model.depot=node
        else:
            model.node_list.append(node)
            model.node_seq_no_list.append(node_seq_no)
        try:
            node.name=df['name'][i]
        except:
            pass
        try:
            node.id=df['id'][i]
        except:
            pass
        node_seq_no=node_seq_no+1
    model.number_of_nodes=len(model.node_list)

(3)初始化参数
在初始化参数时计算网络弧距离,同时对网络弧上的信息素浓度进行初始化,这里默认为10,也可取其他值。

def initParam(model):
    for i in range(model.number_of_nodes):
        for j in range(i+1,model.number_of_nodes):
            d=math.sqrt((model.node_list[i].x_coord-model.node_list[j].x_coord)**2+
                        (model.node_list[i].y_coord-model.node_list[j].y_coord)**2)
            model.distance[i,j]=d
            model.distance[j,i]=d
            model.tau[i,j]=10
            model.tau[j,i]=10

(4)位置更新
在更新蚂蚁位置时,调用 " searchNextNode "函数,依据网络弧信息素浓度及启发式信息搜索蚂蚁下一个可能访问的节点。

def movePosition(model):
    sol_list=[]
    local_sol=Sol()
    local_sol.obj=float('inf')
    for k in range(model.popsize):
        #Random ant position
        nodes_seq=[int(random.randint(0,model.number_of_nodes-1))]
        all_nodes_seq=copy.deepcopy(model.node_seq_no_list)
        all_nodes_seq.remove(nodes_seq[-1])
        #Determine the next moving position according to pheromone
        while len(all_nodes_seq)>0:
            next_node_no=searchNextNode(model,nodes_seq[-1],all_nodes_seq)
            nodes_seq.append(next_node_no)
            all_nodes_seq.remove(next_node_no)
        sol=Sol()
        sol.nodes_seq=nodes_seq
        sol.obj,sol.routes=calObj(nodes_seq,model)
        sol_list.append(sol)
        if sol.obj<local_sol.obj:
            local_sol=copy.deepcopy(sol)
    model.sol_list=copy.deepcopy(sol_list)
    if local_sol.obj<model.best_sol.obj:
        model.best_sol=copy.deepcopy(local_sol)

def searchNextNode(model,current_node_no,SE_List):
    prob=np.zeros(len(SE_List))
    for i,node_no in enumerate(SE_List):
        eta=1/model.distance[current_node_no,node_no]
        tau=model.tau[current_node_no,node_no]
        prob[i]=((eta**model.alpha)*(tau**model.beta))
    #use Roulette to determine the next node
    cumsumprob=(prob/sum(prob)).cumsum()
    cumsumprob -= np.random.rand()
    next_node_no= SE_List[list(cumsumprob > 0).index(True)]
    return next_node_no

(5)信息素更新
这里采用蚁周模型对网络弧信息素进行更新,在具体更新时可根据可行解的nodes_seq属性(TSP问题的解)对所经过的网络弧信息素进行更新;也可根据可行解的routes属性(CVRP问题的解)对所经过的网络弧信息素进行更新。

def upateTau(model):
    rho=model.rho
    for k in model.tau.keys():
        model.tau[k]=(1-rho)*model.tau[k]
    #update tau according to sol.nodes_seq(solution of TSP)
    for sol in model.sol_list:
        nodes_seq=sol.nodes_seq
        for i in range(len(nodes_seq)-1):
            from_node_no=nodes_seq[i]
            to_node_no=nodes_seq[i+1]
            model.tau[from_node_no,to_node_no]+=model.Q/sol.obj

    #update tau according to sol.routes(solution of CVRP)
    # for sol in model.sol_list:
    #     routes=sol.routes
    #     for route in routes:
    #         for i in range(len(route)-1):
    #             from_node_no=route[i]
    #             to_node_no=route[i+1]
    #             model.tau[from_node_no,to_node_no]+=model.Q/sol.obj

(6)目标值计算
目标值计算依赖 " splitRoutes " 函数对TSP可行解分割得到车辆行驶路线和所需车辆数, " calDistance " 函数计算行驶距离。

def splitRoutes(nodes_seq,model):
    num_vehicle = 0
    vehicle_routes = []
    route = []
    remained_cap = model.vehicle_cap
    for node_no in nodes_seq:
        if remained_cap - model.node_list[node_no].demand >= 0:
            route.append(node_no)
            remained_cap = remained_cap - model.node_list[node_no].demand
        else:
            vehicle_routes.append(route)
            route = [node_no]
            num_vehicle = num_vehicle + 1
            remained_cap =model.vehicle_cap - model.node_list[node_no].demand
    vehicle_routes.append(route)
    return num_vehicle,vehicle_routes
def calDistance(route,model):
    distance=0
    depot=model.depot
    for i in range(len(route)-1):
        from_node=model.node_list[route[i]]
        to_node=model.node_list[route[i+1]]
        distance+=math.sqrt((from_node.x_coord-to_node.x_coord)**2+(from_node.y_coord-to_node.y_coord)**2)
    first_node=model.node_list[route[0]]
    last_node=model.node_list[route[-1]]
    distance+=math.sqrt((depot.x_coord-first_node.x_coord)**2+(depot.y_coord-first_node.y_coord)**2)
    distance+=math.sqrt((depot.x_coord-last_node.x_coord)**2+(depot.y_coord - last_node.y_coord)**2)
    return distance
def calObj(nodes_seq,model):
    num_vehicle, vehicle_routes = splitRoutes(nodes_seq, model)
    if model.opt_type==0:
        return num_vehicle,vehicle_routes
    else:
        distance=0
        for route in vehicle_routes:
            distance+=calDistance(route,model)
        return distance,vehicle_routes

(7)绘制收敛曲线

def plotObj(obj_list):
    plt.rcParams['font.sans-serif'] = ['SimHei']  #show chinese
    plt.rcParams['axes.unicode_minus'] = False   # Show minus sign
    plt.plot(np.arange(1,len(obj_list)+1),obj_list)
    plt.xlabel('Iterations')
    plt.ylabel('Obj Value')
    plt.grid()
    plt.xlim(1,len(obj_list)+1)
    plt.show()

(8)输出结果

def outPut(model):
    work=xlsxwriter.Workbook('result.xlsx')
    worksheet=work.add_worksheet()
    worksheet.write(0,0,'opt_type')
    worksheet.write(1,0,'obj')
    if model.opt_type==0:
        worksheet.write(0,1,'number of vehicles')
    else:
        worksheet.write(0, 1, 'drive distance of vehicles')
    worksheet.write(1,1,model.best_sol.obj)
    for row,route in enumerate(model.best_sol.routes):
        worksheet.write(row+2,0,'v'+str(row+1))
        r=[str(i)for i in route]
        worksheet.write(row+2,1, '-'.join(r))
    work.close()

(9)主函数

def run(filepath,Q,alpha,beta,rho,epochs,v_cap,opt_type,popsize):
    """
    :param filepath:Xlsx file path
    :param Q:Total pheromone
    :param alpha:Information heuristic factor
    :param beta:Expected heuristic factor
    :param rho:Information volatilization factor
    :param epochs:Iterations
    :param v_cap:Vehicle capacity
    :param opt_type:Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance
    :param popsize:Population size
    :return:
    """
    model=Model()
    model.vehicle_cap=v_cap
    model.opt_type=opt_type
    model.alpha=alpha
    model.beta=beta
    model.Q=Q
    model.rho=rho
    model.popsize=popsize
    sol=Sol()
    sol.obj=float('inf')
    model.best_sol=sol
    history_best_obj = []
    readXlsxFile(filepath,model)
    initParam(model)
    for ep in range(epochs):
        movePosition(model)
        upateTau(model)
        history_best_obj.append(model.best_sol.obj)
        print("%s/%s, best obj: %s" % (ep,epochs, model.best_sol.obj))
    plotObj(history_best_obj)
    outPut(model)

6. 完整代码

代码和数据文件可获取【私信】:

https://download.youkuaiyun.com/download/python_n/37357242

参考

  1. 汪定伟. 智能优化方法[M]. 高等教育出版社, 2007.
  2. https://blog.youkuaiyun.com/qq_38048756/article/details/109383971
群智能算法实战:蚁群算法(ACO)在路径规划中的高效应用 本文深入探讨了群智能算法中的蚁群算法在路径规划问题中的高效应用。通过模拟蚂蚁觅食行为中的信息素机制,ACO算法能够有效解决旅行商等NP难问题。文章详细解析了算法核心原理、参数调优技巧,并提供了完整的Python实战代码,帮助读者掌握这一强大的优化工具,并将其应用于物流、机器人等实际场景。 阅读详情

相关推荐

【VRP问题】基于遗传结合粒子群求解VRPTW问题

一、粒子群算法简介 粒子群算法是在1995年由Eberhart博士和Kennedy博士一起提出的,它源于对鸟群捕食行为的研究。它的基本核心是利用群体中的个体对信息的共享从而使整个群体的运动在问题求解空间中产生从无序到有序的演化过程,从而获得问题的最优解。设想这么一个场景:一群鸟进行觅食,而远处有一片玉米地,所有的鸟都不知道玉米地到底在哪里,但是它们知道自己当前的位置距离玉米地有多远。那么找到玉米地的最佳策略,也是最简单有效的策略就是搜寻目前距离玉米地最近的鸟群的周围区域。 在PSO中,每个优化问题的..

qq_59747472的博客 437

Python实现VRP常见求解算法——离散粒子群(DPSO)

基于python语言,实现经典粒子群算法(DPSO)对车辆路径规划问题(CVRP)进行求解。

Better.C的博客 6227

【VRP】基于matlab蚁群算法求解多中心的车辆路径规划问题【含Matlab源码 111期】

蚁群算法求解多中心的车辆路径规划问题 完整代码,直接运行,适合小白!可提供运行操作视频!

订阅付费专栏Matlab(奶茶价版),可赠送奶茶价版付费专栏指定代码1份; 4307

【TWCVRP】粒子群算法求解带时间窗的+带容量的车辆路径规划问题(惩罚成本)【含Matlab源码 3034期】

粒子群算法求解带时间窗的+带容量的车辆路径规划问题(惩罚成本) 完整的代码,方可运行;可提供运行操作视频!适合小白!

订阅付费专栏Matlab(奶茶价版)或下载付费资源,可赠送奶茶价版付费专栏指定代码1份; 266

Python中蚁群算法Ant Colony Optimization的设计与实现

在开发蚁群算法的过程中,定义问题结构是一个关键步骤。准确地将实际问题转化为算法能够理解的模型是成功实施算法的前提。本章节将详细介绍如何在Python中构建问题模型,并选择合适的数据结构来支撑算法运行。目标函数是衡量解好坏的标准,其定义依赖于具体问题。在Python中定义目标函数,需要将其表达为一个可计算的函数,该函数接受一定数量的参数(通常是决策变量),并返回一个表示目标值(如成本、利润或适应度)的数值。# 示例:定义一个简单的二次目标函数# 这里solution为决策变量数组。

weixin_31591833的博客 1160

新手避坑指南:在MacBook上为PyTorch正确配置MPS环境,跑通第一个YOLOv8训练

本文详细指导新手如何在MacBook上为PyTorch正确配置MPS环境,并成功运行YOLOv8训练。从环境准备、PyTorch安装到YOLOv8配置和性能调优,提供全面的避坑指南和实用技巧,帮助开发者充分利用Mac的GPU加速能力。

weixin_29100399的博客 229

【进阶一】Python实现MDCVRP常见求解算法——差分进化算法(DE)

基于python语言,实现差分进化算法(DE)对多车场车辆路径规划问题(MDCVRP)进行求解。 目录1. 适用场景2. 求解效果3. 代码分析4. 数据格式5. 分步实现6. 完整代码 1. 适用场景 求解MDCVRP 问题 车辆类型单一 车辆容量不小于需求节点最大需求 多车辆基地 各车场车辆总数满足实际需求 2. 求解效果 (1)收敛曲线 (2)车辆路径 3. 代码分析 车俩路径规划问题按照车场数量可分为单一车场路径规划问题和多车场路径规划问题。针对单一车场条件下仅考虑车辆容量限制的路径规划.

Better.C的博客 1387

缺陷检测-金属表面缺陷检测

1介绍 缺陷检测是工业视觉技术中最重要的组成部分。业务广泛,场景丰富,技术难点高、工作量大。针对不同的场景,选择不同的相机和

huneng1991的专栏 5250

【改进篇】Python实现VRP常见求解算法——蚁群算法(ACO)

基于python语言,实现经典蚁群算法(ACO)对车辆路径规划问题(CVRP)进行求解, 优化代码结构,改进Split函数

Better.C的博客 4770

OpenClaw Browser Relay Extension 鉴权失败与 invalid handshake 问题的终极解决方案

在使用 OpenClaw 浏览器插件 (Browser Relay Extension) 时,许多用户可能会遇到两个主要问题:一是配置端口错误导致的连接失败,二是鉴权失败 (Gateway token rejected)。本文将详细解析这两个问题并提供解决方案。

gerryke的blog 5561

国产射频直采收发器CX8242KA JESD204C调试

杭州诚芯公司的CX8242KA是国内开发的极少数支持JESD204C接口的高速AD、DA,Serdes具备支持接收和发送,并且速率可以到25Gbps,在国内属于领先水平。250M参考时钟输入,AD采样率2.5G,DA采样率10G,3收2发,主通道模式4,反馈通道模式1,基带采样率1250M,线速率20.625G,收发同时配置混频625M。CX8242KA的204C接口模式支持10种模式,在手册上都有说明。2、 支持TX信道编码,RX信道解码,提升健壮性。这里使用模式4,支持双通道模式,并且反馈开启。

RFSOC的博客 6223

4. 【进阶】Python实现VRP常见求解算法——蚁群算法(ACO)

参考笔记 https://github.com/PariseC/Algorithms_for_solving_VRP 1. 适用场景 求解MDCVRP 问题 车辆类型单一 车辆容量不小于需求节点最大需求 多车辆基地 各车场车辆总数满足实际需求 1. 适用场景 求解MDCVRP 问题 车辆类型单一 车辆容量不小于需求节点最大需求 多车辆基地 各车场车辆总数满足实际需求 2. 代码分析 车俩路径规划问题按照车场数量可分为单一车场路径规划问题和多车场路径规划问题。针对单一车场条件下仅考虑车辆容量限制的路径

qq_36744449的博客 2395

DIKW模型实战:用Obsidian打造个人知识库的5个关键步骤

本文详细介绍了如何利用DIKW模型在Obsidian中构建高效个人知识库的5个关键步骤,从数据收集到智慧应用的全流程实践。通过标记系统、信息加工引擎和知识结晶方法,帮助知识工作者实现从原始数据到决策智慧的认知跃迁,提升个人知识管理效率。

gamma的博客 578

4. Python实现VRP常见求解算法——蚁群算法(ACO)

参考笔记 https://github.com/PariseC/Algorithms_for_solving_VRP 1. 适用场景 求解CVRP 车辆类型单一 车辆容量不小于需求节点最大需求 单一车辆基地 2. 问题分析 CVRP问题的解为一组满足需求节点需求的多个车辆的路径集合。 假设某物理网络中共有10个顾客节点,编号为1~10,一个车辆基地,编号为0,在满足车辆容量约束与顾客节点需求约束的条件下,此问题的一个可行解可表示为:[0-1-2-0,0-3-4-5-0,0-6-7-8-0,0-9-10-

qq_36744449的博客 1692

飞常准小程序接口逆向分析:如何破解航班查询的签名机制

本文深度解析了飞常准小程序航班查询接口的安全机制,重点剖析了其基于MD5和参数排序的签名算法。通过逆向分析核心代码,详细阐述了签名生成流程,并提供了Python实现的签名生成器与调试技巧,为开发者理解与模拟此类接口调用提供了实战指南。

zz67890的博客 532

【OpenFOAM】-olaFlow-算例10-wavemakerTank

采用 Flap和Piston两种方式的动网格进行造波

ou_no的博客 2169

【进阶二】Python实现VRPTW常见求解算法——蚁群算法(ACO)

基于python语言,实现经典蚁群算法(ACO)对带有时间窗的车辆路径规划问题(VRPTW )进行求解。

Better.C的博客 3895

Python 爬虫实战:抓取应届生求职网校招岗位信息,助力学子就业

应届生求职网作为国内知名的招聘平台,汇聚了大量企业的校招岗位信息。了解这些岗位信息,对于应届毕业生制定求职策略、企业制定招聘计划以及相关就业市场分析等都具有重要意义。因此,本文将深入探讨如何运用 Python 爬虫技术从应届生求职网平台抓取校招岗位信息,为应届毕业生提供有益的就业信息支持。本文深入探究了利用 Python 爬虫技术从应届生求职网平台抓取校招岗位信息的全流程。从前期的环境搭建、模拟登录,到核心的数据抓取、存储,再到后续的数据分析与可视化,都详细展开讲解并提供代码支持。

u014481728的博客 1301

Python实现蚁群算法求解VRP问题(附完整代码)

Python实现蚁群算法求解VRP问题(附完整代码)

corn1949的博客 1900

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

【进阶六】Python实现SDVRPTW常见求解算法——蚁群算法(ACO)

基于python语言,采用经典蚁群算法(ACO)对 带硬时间窗的需求拆分车辆路径规划问题(SDVRPTW) 进行求解。

Better.C的博客 1384

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

【进阶五】Python实现SDVRP(需求拆分)常见求解算法——蚁群算法(ACO)

基于python语言,采用经典遗传算法(ACO)对 需求拆分车辆路径规划问题(SDVRP) 进行求解。

Better.C的博客 1154

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

蚁群算法(ACO)解决旅行商(TSP)问题的python实现

蚁群算法在组合优化问题中表现出色,尤其是在动态变化的问题环境中。它已被应用于各种实际问题,如物流配送、网络路由优化、图像处理等领域。优势与局限性优势:蚁群算法具有强大的全局搜索能力,能够在大规模搜索空间中有效找到解决方案;同时具备良好的并行性和适应性。局限性:蚁群算法可能需要较多的迭代次数才能收敛,且有可能陷入局部最优解。此外,算法参数的设置对结果影响较大,需要根据具体问题仔细调整。

qq_49370210的博客 2638

探索群体智慧:蚁群算法(ACO)从原理到实践——python实现

蚁群算法通过模拟简单的个体行为涌现出复杂的群体智能,为解决复杂的组合优化问题提供了一种强大而灵活的工具。其分布式、自组织的特性使其具有很强的鲁棒性和扩展性。

Rick_Theseusr的博客 1050

蚁群算法求解VRPTW问题

蚁群算法求解VRPTW问题

2301_79574522的博客 1668

蚁群算法(Ant Colony Optimization, ACO)

蚁群算法(Ant Colony Optimization, ACO)介绍。

欢迎学习交流! 2142

蚁群算法(ACO)实战:从原理到Python代码实现

本文深入解析了蚁群算法(ACO)的核心原理,即模拟蚂蚁觅食行为,通过信息素正反馈机制解决组合优化问题。文章提供了从参数解析到Python代码实现的完整实战教程,以旅行商问题(TSP)为例,手把手指导读者完成算法部署与可视化,并探讨了算法优化技巧与更广泛的应用场景。

nn3456的博客 746
上一篇: Python实现VRP常见求解算法——模拟退火(SA)
下一篇: Python实现VRP常见求解算法——差分进化算法(DE)
Better.C
博客等级 码龄9年 1万+粉丝 72原创
评论 53
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Better.C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值