julia系列17: tsp问题代码整理

news2025/1/10 17:09:35

1. 常用库和基础函数

这里是优化版的函数:

using TSPLIB,LKH,Distances,PyPlot
MaxNum = 10000
tsp=readTSPLIB(:att48)
dist = [round.(Int,euclidean(tsp.nodes[i,:],tsp.nodes[j,:])) for i in 1:tsp.dimension,j in 1:tsp.dimension];
pos(tsp::TSP,t::Vector{Int},i::Int)=tsp.nodes[t[i]==n+1 ? 1 : t[i],:]
total_length(tsp::TSP,t::Vector{Int64})=sum([round.(Int,euclidean(pos(tsp,t,i),pos(tsp,t,i+1))) for i in 1:length(t)-1])
function minimum2(vec)
    i2 = (-1,-1);v2=(MaxNum,MaxNum);for (i,v) in enumerate(vec);if v2[1]>v;v2=(v,v2[1]);i2=(i,i2[1]);elseif v2[2]>v;v2=(v2[1],v);i2=(i2[1],i);end;end
    return i2,v2
end
function greedyConstruct(dist)
    path = [1];for _ in 1:size(dist)[1];c_dist = dist[path[end],:];c_dist[path].=MaxNum;next_id = findmin(c_dist)[2];push!(path,next_id);end
    return path
end
function plot_path(tsp,path)
    t = tsp.nodes[path,:];for p in path;text(tsp.nodes[p,1],tsp.nodes[p,2],p);end;scatter(t[:,1],t[:,2]);plot(t[:,1],t[:,2])
end
function plot_tree(tsp,mst)
    s = tsp.nodes;for p in 1:tsp.dimension;text(s[p,1],s[p,2],p);end;scatter(s[:,1],s[:,2]);for m in mst;plot(s[[m...],1],s[[m...],2],c="b");end
end
function minspantree(dm::AbstractMatrix{T}) where {T<:Real} # accepts views
    mst_edges = Vector{Tuple{Int, Int}}();mst_cost = zero(T);n = size(dm, 1)
    tree_dists = dm[1,:];closest_tree_verts = ones(Int, n);tree_dists[1] = MaxNum
    for _ in 1:(n-1) # need to add n - 1 other verts to tree
        cost, newvert = findmin(tree_dists)
        treevert = closest_tree_verts[newvert];mst_cost += cost
        push!(mst_edges, tuple(sort([treevert, newvert])...))
        tree_dists[newvert] = MaxNum
        for i in 1:n
            if tree_dists[i] >= MaxNum;continue;end
            if tree_dists[i] > dm[i, newvert];tree_dists[i] = dm[i, newvert];closest_tree_verts[i] = newvert;end
        end
    end
    return mst_edges, mst_cost
end

这里是老版的函数

using TSPLIB
using LKH
using Distances
using Random

function pos(tsp::TSP,t::Vector{Int},i::Int)
    n = length(t)
    i = mod(i, n)
    if i == 0
        return tsp.nodes[t[n],1:2]
    else
        return tsp.nodes[t[i],1:2]
    end
end

function pos(b::Vector{Int},i::Int)
    n_b = length(b)
    i = mod(i, n_b)
    if i == 0
        return b[n_b]
    else
        return b[i]
    end
end

function tour_length(tsp::TSP,t::Vector{Int64})
    l = 0
    for i in 1:length(t)
        l += Int.(round.(euclidean(pos(tsp,t,i),pos(tsp,t,i+1))))
    end
    l
end

function greedyConstruct(tsp)
    n = tsp.dimension
    uv = Set{Int}(2:n)
    t = Array{Int64}(undef, n)
    t[1] = 1
    for i in 2:n
        cur = t[i-1]
        mindist = Inf
        ind = 1
        for j in collect(uv)
            dis = round.(Int, euclidean(tsp.nodes[cur,1:2],tsp.nodes[j,1:2]))
            if dis < mindist
                mindist = dis
                ind = j
            end
        end
        t[i] = ind
        pop!(uv,ind)
    end
    return t
end

num = 30
f = "bbz25234"
tsp = readTSP("/Users/chen/Downloads/vlsi/"*f*".tsp")
n = tsp.dimension

# 解析问题文件
t = parse.(Int, readlines("xrb14233.tour")[6:end-3])
totaldist(t)

用LKH求解器先给出一些初始解:

println("start...")
for i in 1:num
    @time t,v = solve_tsp("/Users/chen/Downloads/vlsi/"*f*".tsp";RUNS=1,MAX_TRIALS =150, MAX_SWAPS=100,SEED=i,PI_FILE="pi.txt",TIME_LIMIT=100,CANDIDATE_FILE = "cand.txt") #
    @printf("%d",v)
    ts[i,:]=t
    results[i]= v
end
println("end")

io = open("route.out","w")
for i in 1:size(ts)[1]
    write(io, string(ts[i,:])*"\n")
end
close(io)

# route是初始路线合集,格式如下图
ts = Array{Int32}(undef, (num,n))
results = Array{Int32}(undef,num)
lines = readlines("route.out")
println("start...")
for i in 1:num
    ts[i,:]=Meta.parse(lines[i]) |> eval
    results[i]= totaldist(ts[i,:])
end
println("end")

在这里插入图片描述
接下来设计一下基本数据结构。上述路径使用Array来存储的,

2. 使用MPS GPU加速的2-opt算法

核函数如下:

using Metal
function twooptkernel(dist, t, x, y, z)
    k = thread_position_in_grid_1d()
    n = Int32(size(z)[1])
    if k <= n
        i = x[k]
        j = y[k]
        z[k] = dist[t[i], t[j]]+ dist[t[i==n ? 1 : i+1], t[j==n ? 1 : j+1]] - dist[t[i], t[i==n ? 1 : i+1]] - dist[t[j], t[j==n ? 1 : j+1]]
    end
    return
end

与cpu版本进行对比:

using Random
m = 4000000
x = rand(1:n, m)
y = rand(1:n, m)
z = similar(x)
mx = MtlArray{Int32}(x);
my = MtlArray{Int32}(y);
mz = similar(mx);
mt = MtlArray{Int32}(t);
@time @metal threads=64 grid=6250  twooptkernel(mdist, mt, mx,my,mz)

function cpu(x,y,z)
    for k in 1:m
        i = x[k]
        j = y[k]
        z[k] = dist[t[i], t[j]]+ dist[t[i==n ? 1 : i+1], t[j==n ? 1 : j+1]] - dist[t[i], t[i==n ? 1 : i+1]] - dist[t[j], t[j==n ? 1 : j+1]]
    end
end
@time cpu(x,y,z)

分别为
0.000656 seconds (254 allocations: 6.031 KiB)
以及
5.414779 seconds (74.26 M allocations: 1.168 GiB, 0.61% compilation time)
m = 40000

完整GPU调用代码如下:

for i in 1:200000
    m = 400000
    mx = MtlArray{Int32}(rand(1:n, m));
    my = MtlArray{Int32}(rand(1:n, m));
    mz = similar(mx);
    mt = MtlArray{Int32}(t);
    @metal threads=64 grid=6250  twooptkernel(mdist, mt, mx,my,mz)
    z = Array(mz)
    v,ind = findmin(z)
    if v < 0
        st,ed = mx[ind], my[ind]
        if st>ed
           st,ed = ed,st 
        end
        reverse!(t, st+1, ed)
    end
    if i % 1000 == 0
        println(i,":",totaldist(t))
    end
end

3. LKH算法包

调用方式极其简单:

using LKH
opt_tour, opt_len = solve_tsp(dist)
opt_tour, opt_len = solve_tsp(x, y; dist="EUC_2D")
opt_tour, opt_len = solve_tsp("gr17.tsp")
opt_tour, opt_len = solve_tsp(dist; INITIAL_TOUR_ALGORITHM="GREEDY", RUNS=5)

可用参数参考这篇:https://blog.csdn.net/kittyzc/article/details/114388836
一些常用参数:

RUNS=1, 重复运行次数
MAX_TRIALS =1000, 每次运行最多尝试交换的次数,默认值等于点数。
MAX_SWAPS=1000, 每次交换最多运行swap的次数。
INITIAL_TOUR_FILE = "temp.out", 初始化路径地址
SEED=inum, 每次运行给一个新的seed
PI_FILE="pi-"*f*".txt", 新的cost,计算一次后重复调用
TIME_LIMIT=100, 时间限制
CANDIDATE_FILE = "cand-"*f*".txt", 每个点的近邻,计算一次后重复调用即可

4. 简单遗传算法

每次随机选两条路径(t_ids),并随机从第一条路径t1上选两个点(e_ids),将其中的点按照第二条路径t2的顺序重新排列,产生新的路径t3,对此路径使用LKH算法进行优化,如果距离比t1或者t2短,则进行替换。

iter = 500
t_ids = rand(1:size(ts)[1], (iter,2))
e_ids = rand(1:n, (iter,2))
for inum in 1:iter
    t1i,t2i = t_ids[inum,1], t_ids[inum,2] 
    i1, i2 = e_ids[inum,1], e_ids[inum,2] 
    if i1>i2
        i1,i2 = i2,i1
    end 
    t1 = ts[t1i,:]
    t2 = ts[t2i,:]
    t3 = Array{Int32}(undef, n)
    t3[1:i1] = t1[1:i1]
    t3[i2:end] = t1[i2:end]
    t2ind = 1
    for t3ind in i1:i2
        while !(t2[t2ind] in t1[i1:i2])
            t2ind += 1
        end
        t3[t3ind] = t2[t2ind]
        t2ind+=1
    end
    io = open("temp.out","w")
    write(io, "TYPE : TOUR\nDIMENSION : "*string(n)*"\nTOUR_SECTION\n")
    for i in t3
        write(io, string(i)*"\n")
    end
    write(io, "-1\nEOF\n")
    close(io)
    t3, s3 = solve_tsp("/Users/chen/Downloads/vlsi/"*f*".tsp";RUNS=1,MAX_TRIALS =1000, MAX_SWAPS=1000,INITIAL_TOUR_FILE = "temp.out",SEED=inum,PI_FILE="pi.txt",TIME_LIMIT=100,CANDIDATE_FILE = "cand.txt") #
    sk, skind = findmin(results)

    # replace parents
    if s3 < sk
        print("*",inum,": from ",sk," to ",s3,", ")
        io = open("best"*string(s3)*".out","w")
        write(io, "TYPE : TOUR\nDIMENSION : "*string(n)*"\nTOUR_SECTION\n")
        for i in t3
            write(io, string(i)*"\n")
        end
        write(io, "-1\nEOF\n")
        close(io)
    else
        print(" ",inum,":")
    end
    a,b = t1i,t2i
    if s3 < results[a] <= results[b]
        ts[b,:]=t3
        results[b] = s3
        println(" replace ",b)
    elseif s3 < results[b] <= results[a] 
        ts[a,:]=t3
        results[a] = s3
        println(" replace ",a)
    elseif findmin(results)[1]==findmax(results)[1]
        println(" finish")
        break
    else
        println(" pass")
    end
end

5. ALNS算法

核心代码如下,首先生成breaks,打断这些点位连接的边,然后使用solve_tsp_part重新进行组合:

b_try_num = 1000
b_point_num = 400
@assert b_point_num*2 <= tsp.dimension
b_id_lists = sort(rand(0:tsp.dimension - 2*b_point_num, (b_try_num,b_point_num)),dims = 2)

for i in 1:b_try_num
    b = b_id_lists[i,:] + 2*Vector(1:b_point_num)
    t_imp,v_imp = solve_tsp_part(tsp,t,b)
    if v_imp>0
        t = t_imp
    end
    if i % 100 == 0
        println(tour_length(tsp,t_imp))
    end
end

用于重构的solve_tsp_part和恢复路径的restore_tour代码如下:

function restore_tour(t::Vector{Int64},b::Vector{Int64},b_imp::Vector{Int64})
    n = length(t)
    n_b = length(b)
    t_imp = zeros(Int64,n)
    cur_imp = 1
    for i in 1:n_b
        b_i = div(b_imp[2*i]+1,2) # 在b中的下标
        r = false
        if b_imp[2*i]%2==1
            r = true
        end
        st = pos(b,b_i)
        ed = pos(b,b_i+1)-1
        if ed > st
            mov_imp = ed - st
            if r
                t_imp[cur_imp:cur_imp+mov_imp] = reverse(t[st:ed])
                # for j in reverse(st:ed)
                #     print(t[j],",")
                # end
            else   
                t_imp[cur_imp:cur_imp+mov_imp] = t[st:ed]
                # for j in st:ed
                #     print(t[j],",")
                # end
            end
            cur_imp += mov_imp+1
        else
            if r
                mov_imp = ed - 1
                t_imp[cur_imp:cur_imp+mov_imp] = reverse(t[1:ed])
                cur_imp += mov_imp+1
                mov_imp = n - st
                t_imp[cur_imp:cur_imp+mov_imp] = reverse(t[st:n])
                cur_imp += mov_imp+1
                # for j in reverse(1:ed)
                #     print(t[j],",")
                # end
                # for j in reverse(st:n)
                #     print(t[j],",")
                # end
            else
                mov_imp = n - st
                t_imp[cur_imp:cur_imp+mov_imp] = t[st:n]
                cur_imp += mov_imp+1
                mov_imp = ed - 1
                t_imp[cur_imp:cur_imp+mov_imp] = t[1:ed]
                cur_imp += mov_imp+1
                # for j in st:n
                #     print(t[j],",")
                # end
                # for j in 1:ed
                #     print(t[j],",")
                # end
            end
        end
    end
    t_imp
end

function check_bimp(b_imp::Vector{Int64})
    n_b = div(length(b_imp),2)
    for i in 1:n_b
        if abs(b_imp[2*i]-b_imp[2*i-1])!=1 || div(b_imp[2*i]+1,2)!= div(b_imp[2*i-1]+1,2)
            print(i,":",b_imp[2*i],",",b_imp[2*i-1])
            return false
        end
    end
    return true
end

function solve_tsp_part(tsp::TSP,t::Vector{Int64},b::Vector{Int64}) # b for breaks
    # cal distance matrix
    n = length(t)
    n_b = length(b)
    dist_matrix_b = zeros(Int64,2*n_b,2*n_b)
    for i in 1:n_b
        for j in i+1:n_b
            dist_matrix_b[2*i-1,2*j-1] = dist_matrix_b[2*j-1,2*i-1] = Int(round(euclidean(pos(tsp,t,pos(b,i)),pos(tsp,t,pos(b,j)))))
            dist_matrix_b[2*i-1,2*j] = dist_matrix_b[2*j,2*i-1] = Int(round(euclidean(pos(tsp,t,pos(b,i)),pos(tsp,t, pos(b,j+1)-1 ))))
            dist_matrix_b[2*i,2*j-1] = dist_matrix_b[2*j-1,2*i] = Int(round(euclidean(pos(tsp,t,pos(b,i+1)-1  ),pos(tsp,t,b[j]))))
            dist_matrix_b[2*i,2*j] = dist_matrix_b[2*j,2*i] = Int(round(euclidean(pos(tsp,t,pos(b,i+1)-1 ),pos(tsp,t,pos(b,j+1)-1 ))))
        end
    end
    max_element = maximum(dist_matrix_b)
    for i in 1:n_b
        for j in i+1:n_b
            dist_matrix_b[2*i-1,2*j-1] += max_element
            dist_matrix_b[2*j-1,2*i-1] += max_element
            dist_matrix_b[2*i-1,2*j] += max_element
            dist_matrix_b[2*j,2*i-1] += max_element
            dist_matrix_b[2*i,2*j-1] += max_element
            dist_matrix_b[2*j-1,2*i] += max_element
            dist_matrix_b[2*i,2*j] += max_element
            dist_matrix_b[2*j,2*i] += max_element
        end
    end
    # for i in 1:n_b-1
    #     dist_matrix_b[2*i,2*i-1] = dist_matrix_b[2*i-1,2*i] = -max_element
    # end
    b_imp,v_imp = solve_tsp(dist_matrix_b;runs = 1,MAX_TRIALS =50, MAX_SWAPS=400)
    v_imp -= max_element*n_b
    if check_bimp(b_imp)
        v = 0
        for i in 1:n_b
            v +=  Int(round(euclidean(pos(tsp,t,pos(b,i)),pos(tsp,t, pos(b,i)-1 ))))
        end
        imp = v-v_imp
        if imp > 0
            return restore_tour(t,b,b_imp), imp
        else
            return t, 0
        end
    else
        return b_imp, -1
    end
end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1905330.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【机器学习】基于线性回归的医疗费用预测模型

文章目录 一、线性回归定义和工作原理假设表示 二、导入库和数据集矩阵表示可视化 三、成本函数向量的内积 四、正态方程五、探索性数据分析描述性统计检查缺失值数据分布图相关性热图保险费用分布保险费用与性别和吸烟情况的关系保险费用与子女数量的关系保险费用与地区和性别…

软件架构之数据库系统(2)

软件架构之数据库系统&#xff08;2&#xff09; 3.4 事务管理3.4.1 并发控制3.4.2 故障与恢复 3.5 备份与恢复3.6分布式数据库系统3.6.1分布式数据库的概念3.6.2 分布式数据库的架构 3.7 数据仓库3.7.1 数据仓库的概念3.7.2数据仓库的结构3.7.3 数据仓库的实现方法 3.8 数据挖…

【机器学习实战】Datawhale夏令营:Baseline精读笔记2

# AI夏令营 # Datawhale # 夏令营 在原有的Baseline上除了交叉验证&#xff0c;还有一种关键的优化方式&#xff0c;即特征工程。 如何优化特征&#xff0c;关系着我们提高模型预测的精准度。特征工程往往是对问题的领域有深入了解的人员能够做好的部分&#xff0c;因为我们要…

用QFramework重构飞机大战(Siki Andy的)(下01)(06-0? 游戏界面及之后的所有面板)

GitHub // 官网的 全民飞机大战&#xff08;第一季&#xff09;-----框架设计篇&#xff08;Unity 2017.3&#xff09; 全民飞机大战&#xff08;第二季&#xff09;-----游戏逻辑篇&#xff08;Unity 2017.3&#xff09; 全民飞机大战&#xff08;第三季&#xff09;-----完善…

CGAL计算凸包(OSG进行可视化)

目录 一、什么是凸包 二、运行步骤 1、安装依赖项 2、编译osg库 3、运行代码 4、运行截图 一、什么是凸包 凸包是计算几何中的一个基本概念,用来描述一个点集的最小凸包围形。具体来说,给定一个点集,凸包是包含该点集的最小凸多边形或凸多面体。 二维凸包:在二维平面…

linux RTC时钟时间出现了明显的偏移

RTC时钟时间出现了明显的偏移 1、开发环境2、问题阐述3、验证问题3.1、首先去排查了硬件电路和芯片电压不稳定的问题。3.2、晶振的问题。3.3、芯片本身3.4、芯片寄存器 4、代码修改 1、开发环境 平台&#xff1a;imx6ul kernel版本&#xff1a;linux4.1.5 RTC芯片&#xff1a;…

CSS技巧:纯CSS实现文字渐变动画效果

文字渐变动画&#xff0c;可以实现的有两种&#xff1a;一种是一行文字整体变化颜色&#xff1b;另一种一行文字依次变化颜色。接下来&#xff0c;我就介绍一下这两种文字渐变的实现过程。 布局代码&#xff1a; <div class"con"><div class"animate…

Redis基本命令源码解析-有序集合相关命令

1. zadd 将一个或多个member和score加入到有序集合对应的key中 zadd key [nx|xx] [ch] [incr] score1 member1 score2 member2 ... 调用zaddCommand-->zaddGenericCommand 1.1 zaddGenericCommand 从第3个参数开始解析,参数循环,按位与到flag中 如果有nx,则只做添加…

04.C1W3.Vector Space Models

往期文章请点这里 目录 Vector Space ModelsWord by Word and Word by DocWord by Document DesignWord by Document DesignVector Space Euclidean DistanceEuclidean distance for n-dimensional vectors Euclidean distance in PythonCosine Similarity: IntuitionCosine S…

关于新装Centos7无法使用yum下载的解决办法

起因 之前也写了一篇类似的文章&#xff0c;但感觉有漏洞&#xff0c;这次想直接把漏洞补齐。 问题描述 在我们新装的Centos7中&#xff0c;如果想要用C编程&#xff0c;那就必须要用到yum下载&#xff0c;但是&#xff0c;很多新手&#xff0c;包括我使用yum下载就会遇到一…

在DevEco运行typeScript代码,全网详细解决执行Set-ExecutionPolicy RemoteSigned报出的错

目录 基本思路 网络推荐 本人实践 如下操作,报错: 基本思路 //在DevEco运行typeScript代码 /** * 1.保证node -v出现版本,若没有,配置环境变量(此电脑-属性-高级系统变量配置-path-粘贴路径);DevEco在local.properties中可看到当前nodejs的路径 * 2.npm install …

202406 CCF-GESP Python 四级试题及详细答案注释

202406 CCF-GESP Python 四级试题及详细答案注释 1 单选题(每题 2 分,共 30 分)第 1 题 小杨父母带他到某培训机构给他报名参加CCF组织的GESP认证考试的第1级,那他可以选择的认证语言有几种?( ) A. 1 B. 2 C. 3 D. 4答案:C解析:目前CCF组织的GESP认证考试有C++、Pyth…

想知道你的电脑能不能和如何升级RAM吗?这里有你想要的一些提示

考虑给你的电脑增加更多的RAM,但不确定从哪里开始?本指南涵盖了有关升级Windows PC或笔记本电脑中RAM的所有信息。 你需要升级RAM吗 在深入研究升级RAM的过程之前,评估是否需要升级是至关重要的。你是否经历过系统滞后、频繁的BSOD错误或应用程序和程序突然崩溃?这些症状…

天猫返利软件草柴APP如何领取天猫粉丝福利购大额优惠券?

天猫购物为什么要使用草柴APP领大额优券&#xff1f; 草柴APP是一款购物省钱工具。通过草柴APP可以查询领取淘宝、天猫、京东等大额优惠券享受券后价优惠&#xff0c;确认收货后再回到草柴APP提取返利&#xff0c;让购物实现多重优惠更划算。下图是直接购买和使用草柴APP领取天…

成人高考报名条件及收费标准详解

成人高考报名条件及收费标准详解 您想通过成人高考改变自己的命运&#xff0c;但不知道报名条件和收费标准&#xff1f;本文将为您详细介绍成人高考报名条件和收费标准&#xff0c;并为您提供专业的成人教育服务。 深圳成人高考www.shenzhixun.com 成人高考报名条件 成人高考…

java Lock接口

在 Java 中&#xff0c;Lock 接口的实现类ReentrantLock 类提供了比使用 synchronized 方法和代码块更广泛的锁定机制。 简单示例&#xff1a; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockExampl…

pyrender 离线渲染包安装教程

pyrender 离线渲染包安装教程 安装 安装 官方安装教程:https://pyrender.readthedocs.io/en/latest/install/index.html#installmesa 首先 pip install pyrenderclang6.0安装 下载地址:https://releases.llvm.org/download.html#6.0.0 注意下好是叫&#xff1a;clangllvm-6…

HCIE之IPV6三大动态协议ISIS BGP (十五)

IPV6 1、三大动态路由协议ipv61.1、ISIS1.1.1、ISIS多拓扑实验&#xff08;需要详细看下lsdb verbose&#xff09;1.2、ISIS TLV简单总结 1.2、BGP 2、IPv6 隧道技术2.1、ipv6手工隧道2.1.1、ipv6 gre手工隧道2.1.1.1、 ipv6、ipv4基础配置&#xff08;省略&#xff09;2.1.1.2…

面向在校生,20万总奖金!讯飞星火杯大模型赛事开发报名

Datawhale赛事 赛事&#xff1a;2024星火杯&#xff0c;大模型应用创新赛 2023年科大讯飞“星火杯”大赛吸引了来自海内外498所高校&#xff0c;1585名大学生开发者参与。为深入赋能高校大学生开发者&#xff0c;持续搭建大学生创业创新平台&#xff0c;2024年科大讯飞“星火杯…

时序预测 | Matlab实现TCN-Transformer的时间序列预测

时序预测 | Matlab实现TCN-Transformer的时间序列预测 目录 时序预测 | Matlab实现TCN-Transformer的时间序列预测效果一览基本介绍程序设计 效果一览 基本介绍 基于TCN-Transformer模型的时间序列预测&#xff0c;可以用于做光伏发电功率预测&#xff0c;风速预测&#xff0c;…