自动驾驶算法(九):多项式轨迹与Minimun Snap原理与Matab代码详解

目录

1 为什么需要轨迹优化

2 代码解析

3 完整代码


1 为什么需要轨迹优化

        我们利用前八篇所学的博客可以利用RRT、A*、遗传算法等设计出一条折线轨迹,轨迹优化就是在路径优化的基础上将折线优化成曲线,这样更加有利于无人机的飞行。

        那么什么是多项式轨迹呢?

        每段轨迹的路程以t为变量的函数表示出来就是多项式轨迹。

        我们用三段轨迹表示这段路程(以时间t作为自变量):

        那么我们的任务就是求解参数向量p确定轨迹,t_0,t_1,t_2与路程成正比的因此我们可以提前算出。

        那么我们轨迹的要求是什么呢?

        优化目标为:

        这个优化的目的是使加速度尽可能的小:那么速度也是尽可能地小,对无人机动力要求就不那么大了。

        具体推导如下:

        其实我们就要算出来个Q矩阵,里面的r是rows的意思,c是cols的意思。

        其实就是一个二次规划问题?

        也就是求在Ap=b约束下最小的p^TQp

2 代码解析

        我们先来运行一下:

        所在位置为*的就是我们航行的路径点,不同颜色的就是几段。

        我们因此要先设置起点的速度和加速度、终点的速度和加速度、还有总时间、我们根据总时间还有路径的长度去分配时间:

function demo1_minimum_snap_simple()clear,clc;% condition% 航路点 起点、终点、中间的这些点waypts = [0,0;1,2;2,0;4,5;5,2]';% 起点、终点速度加速度      v0 = [0,0];a0 = [0,0];v1 = [0,0];a1 = [0,0];% 总时间T = 5; % 计算每一段轨迹的时间% 输入参数为航路点 + 总时间ts = arrangeT(waypts,T);% 设置多项式的阶数n_order = 5;

        我们看一下怎么给各段路程分配时间的:

function ts = arrangeT(waypts,T)% 这一行代码计算了相邻路径点之间的差值。假设 waypts 是一个矩阵,每一列代表一个路径点的坐标,% 那么 waypts(:,2:end) 选择了除了第一个路径点之外的所有路径点,waypts(:,1:end-1) 选择了除了最后一个路径点之外的所有路径点,% 然后两者相减,得到了相邻路径点之间的位移。% waypts:% 0 1 2 4 5% 0 2 0 5 2% waypts(:,2:end)% 冒号表示取到了所有的行,取到了2到最后一列% 1 2 4 5% 2 0 5 2% 0 1 2 4  = 1  1  2  1% 0 2 0 5  = 2 -2  5 -3  其实就是相邻的点进行相减x = waypts(:,2:end) - waypts(:,1:end-1);% 计算了相邻路径点之间的欧几里得距离。x.^2 将 x 中的每个元素平方,然后 sum(x.^2,1) 对每列进行求和,% 最后 .^0.5 对每个和取平方根,得到相邻路径点之间的欧几里得距离。dist = sum(x.^2,1).^0.5;% 计算了一个缩放因子 k,它是总时间 T 与所有相邻路径点之间的距离之和的比值。k = T/sum(dist);% 构建了时间戳 ts。cumsum(dist*k) 计算了距离的累积和,然后在前面加了一个零,以确保起始时间戳为零。ts = [0 cumsum(dist*k)];
end

        我们指定了总时间T=5秒,这里做的就是根据路程进行线性分段。

    %% XY轴分开计算% 传入参数 第一行的所有列就是所有的x 每一段的时间 多项式阶 起点终点的加速度polys_x = minimum_snap_single_axis_simple(waypts(1,:),ts,n_order,v0(1),a0(1),v1(1),a1(1));polys_y = minimum_snap_single_axis_simple(waypts(2,:),ts,n_order,v0(2),a0(2),v1(2),a1(2));

        这里就是重头戏了,进行路径规划,包括求Q矩阵与约束的构建。

% 传入参数 第一行的所有列就是所有的x 每一段的时间 多项式阶 起点终点的加速度
function polys = minimum_snap_single_axis_simple(waypts,ts,n_order,v0,a0,ve,ae)
% 起点终点的位置
p0 = waypts(1);
pe = waypts(end);% 多项式的段数:航路点-1
n_poly = length(waypts)-1;
% 参数个数 = 阶数+1
n_coef = n_order+1;% 构建优化目标 优化目标的数量为多项式的段数
Q_all = [];
for i=1:n_poly% 构建对角矩阵(有几个多项式就有几个Q)% 在每次循环中,它调用了一个名为 computeQ 的函数% 传递了四个参数:n_order(多项式的阶数)、3(对jack 4阶导数进行优化)、ts(i)这一段的起始时间 和 ts(i+1)这一段的结束时间。% computeQ 函数的返回值是一个对角矩阵,这个对角矩阵将会被加入到 Q_all 中,通过 blkdiag 函数实现对 Q_all 的更新。Q_all = blkdiag(Q_all,computeQ(n_order,3,ts(i),ts(i+1)));

        这里我们传进来了起点和终点的x坐标。n_poly表示多项式的段数,也就是我们求的路程有几段,为航路点个数-1 = 4段。n_coef就是p矩阵的阶数,我们采用5阶(n_order)项+一个常数项的表示方法,即:

% 传入参数 个体的路径 地图 一行有多少个元素x
% 它告诉 MATLAB 这是一个名为 generate_continuous_path 的函数,它接受三个输入参数 single_pop,G 和 x,并且它会返回一个名为 single_new_pop 的变量。
function [single_new_pop] = generate_continuous_path(single_pop, G, x)
i = 1;
single_new_pop = single_pop;
% 这行代码调用了 size 函数来获取变量 single_new_pop 的大小,并将结果存储在了 single_path_num 变量中。
% 在这里,使用了波浪线 ~ 来表示忽略了 size 函数返回的第一个值(也就是行数),只保留了列数。
% single_new_pop 是一个 1 * 20的向量
% single_path_num 存储了路径经过的点的数量
[~, single_path_num] = size(single_new_pop);

% 遍历每一列 1-20
while i ~= single_path_num
    % 点i所在列 (从左到右编号)
    x_now = mod(single_new_pop(1, i), x) + 1; 
    % 点i所在行 (从上到下编号)
    y_now = fix(single_new_pop(1, i) / x) + 1;
    % 点i+1所在行 (从上到下编号)
    x_next = mod(single_new_pop(1, i + 1), x) + 1;
    y_next = fix(single_new_pop(1, i + 1) / x) + 1;
    
    % 初始化最大迭代次数
    max_iteration = 0;
    
    % 如果他们不相连的话
    while max(abs(x_next - x_now), abs(y_next - y_now)) > 1
        x_insert = floor((x_next + x_now) / 2);
        y_insert = floor((y_next + y_now) / 2);
        
        % 取得两者中点值
        if G(y_insert, x_insert) == 0  
            % 栅格值
            num_insert = (x_insert - 1) + (y_insert - 1) * x;
            % single_new_pop 是一个数组,这段代码的目的是将 num_insert 插入到 single_new_pop 的第 i 个位置之后。
            % single_new_pop(1, 1:i) 表示取 single_new_pop 中第1行,从第1列到第i列的元素。
            % single_new_pop(1, i+1:end) 表示取 single_new_pop 中第1行,从第i+1列到最后一列的元素。
            single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
            
        % 如果是障碍物的话
        else   
            % 它检查该点左面是否有路径 
            % (x_insert - 2) + (y_insert - 1) * x 是否不等于 single_new_pop(1, i)。
            if G(y_insert, x_insert - 1) == 0 && ((x_insert - 2) + (y_insert - 1) * x ~= single_new_pop(1, i)) && ((x_insert - 2) + (y_insert - 1) * x ~= single_new_pop(1, i+1))
                x_insert = x_insert - 1;
                % 索引号
                num_insert = (x_insert - 1) + (y_insert - 1) * x;
                % 插入
                single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
                               
            elseif G(y_insert, x_insert + 1) == 0 && (x_insert + (y_insert - 1) * x ~= single_new_pop(1, i)) && (x_insert + (y_insert - 1) * x ~= single_new_pop(1, i+1))
                x_insert = x_insert + 1;
                num_insert = (x_insert - 1) + (y_insert - 1) * x;
                single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
                
            elseif G(y_insert + 1, x_insert) == 0 && ((x_insert - 1) + y_insert * x ~= single_new_pop(1, i)) && ((x_insert - 1) + y_insert * x ~= single_new_pop(1, i+1))
                y_insert = y_insert + 1;
                num_insert = (x_insert - 1) + (y_insert - 1) * x;
                single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];

            elseif  G(y_insert - 1, x_insert) == 0 && ((x_insert - 1) + (y_insert - 2) * x ~= single_new_pop(1, i)) && ((x_insert - 1) + (y_insert-2) * x ~= single_new_pop(1, i+1))
                y_insert = y_insert - 1;
                num_insert = (x_insert - 1) + (y_insert - 1) * x;
                single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
                
            % 左右上下都是占据的则删去路径
            else
                %break_pop = single_new_pop
                single_new_pop = [];
                break
            end    
        end
        
        x_next = x_insert;
        y_next = y_insert;
        max_iteration = max_iteration + 1;
        if max_iteration > 20000
            single_new_pop = [];
            break
        end
        
    end
    
    if isempty(single_new_pop)
        break
    end
    
    [~, single_path_num] = size(single_new_pop);
    i = i + 1;
end

        了解这些后,我们通过ComputeQ计算Q矩阵,并通过blkdiag合并一个个Q矩阵,最终组成如下形式:

Q = \begin{bmatrix} Q_1 & & & & \\ & Q_2& & & \\ & & ... & & \\ & & &... & \\ & & & & Q_k \end{bmatrix}

        其中k为多项式的段数,也就是说有几段路程,就有几个Q矩阵。

        我们看一下Q矩阵的计算方法:

% n:polynormial order
% r:derivertive order, 1:minimum vel 2:minimum acc 3:minimum jerk 4:minimum snap
% t1:start timestamp for polynormial
% t2:end timestap for polynormial
% n=5 五次多项式拟合路径 r=3 用jerk模拟 t1 t2 
function Q = computeQ(n,r,t1,t2)
% (n-r)*2+1 = (5-3)*2+1 = 5
T = zeros((n-r)*2+1,1);
for i = 1:(n-r)*2+1T(i) = t2^i-t1^i;
end
% 理论说过Q是n+1 * n+1的维度  也就是7*7的维度  r是3 表示用jerk进行优化
% 它的矩阵就右下角有值 
Q = zeros(n+1);
for i = r+1:n+1     % 行 从r+1开始,因为前r行都是0,在PPT中r=4。在我们的实例中r=3for j = i:n+1   % 列 从r+1开始k1 = i-r-1; %对应r-3  行-r-1k2 = j-r-1; %对应c-3  列-r-1k = k1+k2+1;% r-3+c-3+1% prod是连乘的意思  prod(k1+1:k1+r)= r-3+1 *...* r-3+3 =% (r-3)(r-2)(r-1)r  (c-3)(c-2)(c-1)c k就是参数 Q(i,j) = prod(k1+1:k1+r)*prod(k2+1:k2+r)/k*T(k);Q(j,i) = Q(i,j);end
end
%Q

        这里我们传来的n=5,即用五次项拟合曲线,r=4用三阶导数去求极值。

        T矩阵就是后面的那块:t_{i}^{r+c-7}-t_{i-1}^{r+c-7}

        这里是对应于4阶snap来说的,我们用三阶作为优化目标那么我们的T矩阵就应当是t_{i}^{r-3+c-3+1}-t_{i-1}^{r-3+c-3+1}。前三排前三列是0的,因此有值的就是第4行到第n+1=6行。因为是对角矩阵,我们只需算出其中的一半也就是6个值。如下Q矩阵:

      我们初始化Q矩阵为(n+1,n+1)的方阵,从r+1行也就是3+1=4行开始赋值,比如第四行,从第四列一直到第n+1列也就是第6列,再比如第五行,从第五列一直到第n+1列也就是第6列。

        首先计算r-3,也就是行-3,i表示遍历哪一行,j表示遍历哪一列,因此我们不妨想想当i与j都为4的时候,行-3对应4-3-1!=0,我们补足-1就是0了。k对应r-3+c-3+1。t_{i}^{r-3+c-3+1}-t_{i-1}^{r-3+c-3+1}就是T(k)。

        这里我们就理解T矩阵的赋值了,因为它所包含的最高项的次数为r-3+c-3+1的max r和c,r和cmax也就是n+1,因此它的最高项次数也就是 (n-3)*2 + 1。到此,我们的Q矩阵就构造完毕啦。

        我们打印一下Q矩阵:

        我们来建立约束方程:

% 传入参数 个体的路径 地图 一行有多少个元素x
% 它告诉 MATLAB 这是一个名为 generate_continuous_path 的函数,它接受三个输入参数 single_pop,G 和 x,并且它会返回一个名为 single_new_pop 的变量。
function [single_new_pop] = generate_continuous_path(single_pop, G, x)
i = 1;
single_new_pop = single_pop;
% 这行代码调用了 size 函数来获取变量 single_new_pop 的大小,并将结果存储在了 single_path_num 变量中。
% 在这里,使用了波浪线 ~ 来表示忽略了 size 函数返回的第一个值(也就是行数),只保留了列数。
% single_new_pop 是一个 1 * 20的向量
% single_path_num 存储了路径经过的点的数量
[~, single_path_num] = size(single_new_pop);

% 遍历每一列 1-20
while i ~= single_path_num
    % 点i所在列 (从左到右编号)
    x_now = mod(single_new_pop(1, i), x) + 1; 
    % 点i所在行 (从上到下编号)
    y_now = fix(single_new_pop(1, i) / x) + 1;
    % 点i+1所在行 (从上到下编号)
    x_next = mod(single_new_pop(1, i + 1), x) + 1;
    y_next = fix(single_new_pop(1, i + 1) / x) + 1;
    
    % 初始化最大迭代次数
    max_iteration = 0;
    
    % 如果他们不相连的话
    while max(abs(x_next - x_now), abs(y_next - y_now)) > 1
        x_insert = floor((x_next + x_now) / 2);
        y_insert = floor((y_next + y_now) / 2);
        
        % 取得两者中点值
        if G(y_insert, x_insert) == 0  
            % 栅格值
            num_insert = (x_insert - 1) + (y_insert - 1) * x;
            % single_new_pop 是一个数组,这段代码的目的是将 num_insert 插入到 single_new_pop 的第 i 个位置之后。
            % single_new_pop(1, 1:i) 表示取 single_new_pop 中第1行,从第1列到第i列的元素。
            % single_new_pop(1, i+1:end) 表示取 single_new_pop 中第1行,从第i+1列到最后一列的元素。
            single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
            
        % 如果是障碍物的话
        else   
            % 它检查该点左面是否有路径 
            % (x_insert - 2) + (y_insert - 1) * x 是否不等于 single_new_pop(1, i)。
            if G(y_insert, x_insert - 1) == 0 && ((x_insert - 2) + (y_insert - 1) * x ~= single_new_pop(1, i)) && ((x_insert - 2) + (y_insert - 1) * x ~= single_new_pop(1, i+1))
                x_insert = x_insert - 1;
                % 索引号
                num_insert = (x_insert - 1) + (y_insert - 1) * x;
                % 插入
                single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
                               
            elseif G(y_insert, x_insert + 1) == 0 && (x_insert + (y_insert - 1) * x ~= single_new_pop(1, i)) && (x_insert + (y_insert - 1) * x ~= single_new_pop(1, i+1))
                x_insert = x_insert + 1;
                num_insert = (x_insert - 1) + (y_insert - 1) * x;
                single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
                
            elseif G(y_insert + 1, x_insert) == 0 && ((x_insert - 1) + y_insert * x ~= single_new_pop(1, i)) && ((x_insert - 1) + y_insert * x ~= single_new_pop(1, i+1))
                y_insert = y_insert + 1;
                num_insert = (x_insert - 1) + (y_insert - 1) * x;
                single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];

            elseif  G(y_insert - 1, x_insert) == 0 && ((x_insert - 1) + (y_insert - 2) * x ~= single_new_pop(1, i)) && ((x_insert - 1) + (y_insert-2) * x ~= single_new_pop(1, i+1))
                y_insert = y_insert - 1;
                num_insert = (x_insert - 1) + (y_insert - 1) * x;
                single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
                
            % 左右上下都是占据的则删去路径
            else
                %break_pop = single_new_pop
                single_new_pop = [];
                break
            end    
        end
        
        x_next = x_insert;
        y_next = y_insert;
        max_iteration = max_iteration + 1;
        if max_iteration > 20000
            single_new_pop = [];
            break
        end
        
    end
    
    if isempty(single_new_pop)
        break
    end
    
    [~, single_path_num] = size(single_new_pop);
    i = i + 1;
end

%求解F(不等式) 构建全是0的向量
b_all = zeros(size(Q_all,1),1);% 构建等式约束 4K+2 多项式的个数*每个项的系数
Aeq = zeros(4*n_poly+2,n_coef*n_poly);
beq = zeros(4*n_poly+2,1);% 起点/终点的位置速度和加速度  (6 equations)
% 1-3行 第一个参数到n_order+1=6 位置、速度、加速度
Aeq(1:3,1:n_coef) = [calc_tvec(ts(1),n_order,0);calc_tvec(ts(1),n_order,1);calc_tvec(ts(1),n_order,2)];
% 终点约束4-6
Aeq(4:6,n_coef*(n_poly-1)+1:n_coef*n_poly) = ...[calc_tvec(ts(end),n_order,0);calc_tvec(ts(end),n_order,1);calc_tvec(ts(end),n_order,2)];
beq(1:6,1) = [p0,v0,a0,pe,ve,ae]';

% r=0:pos  1:vel  2:acc 3:jerk
% n_order 多项式的阶数
% t       第i段占据的时间
% r 0 1 2 对应 位置 速度 加速度
function tvec = calc_tvec(t,n_order,r)tvec = zeros(1,n_order+1);for i=r+1:n_order+1tvec(i) = prod(i-r:i-1)*t^(i-r-1);end
end

        回顾一下,我们n_poly,它的值为多项式的段数也就是航路点-1,本例中n_poly =4

        n_coef为多项式的次数+1,这里我们为6。

        先看一下它的形式吧:我们打印一下约束方程的Aeq

        它的行数为18(4*n_poly+2),列数为24(n_coef *n_poly )。我们看看它里面存储的是什么吧!

        1-6行我们加入起点和终点的约束(位移、速度、加速度):

% 起点/终点的位置速度和加速度  (6 equations)
% 1-3行 第一个参数到n_order+1=6 位置、速度、加速度
Aeq(1:3,1:n_coef) = [calc_tvec(ts(1),n_order,0);calc_tvec(ts(1),n_order,1);calc_tvec(ts(1),n_order,2)];
% 终点约束4-6
Aeq(4:6,n_coef*(n_poly-1)+1:n_coef*n_poly) = ...[calc_tvec(ts(end),n_order,0);calc_tvec(ts(end),n_order,1);calc_tvec(ts(end),n_order,2)];

        起点约束放在起点的位置上,因为一个约束是有5阶+1个常数项的,因此一个约束占据6列。一共4段路线,是这么来的24行。

        从第七行开始固定中间的点。从第七行开始到第十行。

neq = 6;
% 从第七行开始
for i=1:n_poly-1neq=neq+1;Aeq(neq,n_coef*i+1:n_coef*(i+1)) = calc_tvec(ts(i+1),n_order,0);beq(neq) = waypts(i+1);
end

        位置为行数,一个占据自己的六个位置,如下:

        下面开始连续性约束:

% 段数-1 continuous constraints  ((n_poly-1)*3 equations)
for i=1:n_poly-1tvec_p = calc_tvec(ts(i+1),n_order,0);tvec_v = calc_tvec(ts(i+1),n_order,1);tvec_a = calc_tvec(ts(i+1),n_order,2);neq=neq+1;Aeq(neq,n_coef*(i-1)+1:n_coef*(i+1))=[tvec_p,-tvec_p];neq=neq+1;Aeq(neq,n_coef*(i-1)+1:n_coef*(i+1))=[tvec_v,-tvec_v];neq=neq+1;Aeq(neq,n_coef*(i-1)+1:n_coef*(i+1))=[tvec_a,-tvec_a];
end

        对位移、速度、加速度进行约束。n_coef*(i-1)+1:n_coef*(i+1)代表每一次处理一个点,如下:

        圈起来的就是一对邻接点的位移、速度、加速度。

        我们添加完约束之后,开始求解

Aieq = [];
bieq = [];p = quadprog(Q_all,b_all,Aieq,bieq,Aeq,beq);polys = reshape(p,n_coef,n_poly);

        我们这里没有不等式约束,故设置Q_all,b_all为空,我们求解的变量就是p。

        是不是很简单呢?

        看一下运行结果:

3 完整代码

% 传入参数 个体的路径 地图 一行有多少个元素x
% 它告诉 MATLAB 这是一个名为 generate_continuous_path 的函数,它接受三个输入参数 single_pop,G 和 x,并且它会返回一个名为 single_new_pop 的变量。
function [single_new_pop] = generate_continuous_path(single_pop, G, x)
i = 1;
single_new_pop = single_pop;
% 这行代码调用了 size 函数来获取变量 single_new_pop 的大小,并将结果存储在了 single_path_num 变量中。
% 在这里,使用了波浪线 ~ 来表示忽略了 size 函数返回的第一个值(也就是行数),只保留了列数。
% single_new_pop 是一个 1 * 20的向量
% single_path_num 存储了路径经过的点的数量
[~, single_path_num] = size(single_new_pop);% 遍历每一列 1-20
while i ~= single_path_num% 点i所在列 (从左到右编号)x_now = mod(single_new_pop(1, i), x) + 1; % 点i所在行 (从上到下编号)y_now = fix(single_new_pop(1, i) / x) + 1;% 点i+1所在行 (从上到下编号)x_next = mod(single_new_pop(1, i + 1), x) + 1;y_next = fix(single_new_pop(1, i + 1) / x) + 1;% 初始化最大迭代次数max_iteration = 0;% 如果他们不相连的话while max(abs(x_next - x_now), abs(y_next - y_now)) > 1x_insert = floor((x_next + x_now) / 2);y_insert = floor((y_next + y_now) / 2);% 取得两者中点值if G(y_insert, x_insert) == 0  % 栅格值num_insert = (x_insert - 1) + (y_insert - 1) * x;% single_new_pop 是一个数组,这段代码的目的是将 num_insert 插入到 single_new_pop 的第 i 个位置之后。% single_new_pop(1, 1:i) 表示取 single_new_pop 中第1行,从第1列到第i列的元素。% single_new_pop(1, i+1:end) 表示取 single_new_pop 中第1行,从第i+1列到最后一列的元素。single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];% 如果是障碍物的话else   % 它检查该点左面是否有路径 % (x_insert - 2) + (y_insert - 1) * x 是否不等于 single_new_pop(1, i)。if G(y_insert, x_insert - 1) == 0 && ((x_insert - 2) + (y_insert - 1) * x ~= single_new_pop(1, i)) && ((x_insert - 2) + (y_insert - 1) * x ~= single_new_pop(1, i+1))x_insert = x_insert - 1;% 索引号num_insert = (x_insert - 1) + (y_insert - 1) * x;% 插入single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];elseif G(y_insert, x_insert + 1) == 0 && (x_insert + (y_insert - 1) * x ~= single_new_pop(1, i)) && (x_insert + (y_insert - 1) * x ~= single_new_pop(1, i+1))x_insert = x_insert + 1;num_insert = (x_insert - 1) + (y_insert - 1) * x;single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];elseif G(y_insert + 1, x_insert) == 0 && ((x_insert - 1) + y_insert * x ~= single_new_pop(1, i)) && ((x_insert - 1) + y_insert * x ~= single_new_pop(1, i+1))y_insert = y_insert + 1;num_insert = (x_insert - 1) + (y_insert - 1) * x;single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];elseif  G(y_insert - 1, x_insert) == 0 && ((x_insert - 1) + (y_insert - 2) * x ~= single_new_pop(1, i)) && ((x_insert - 1) + (y_insert-2) * x ~= single_new_pop(1, i+1))y_insert = y_insert - 1;num_insert = (x_insert - 1) + (y_insert - 1) * x;single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];% 左右上下都是占据的则删去路径else%break_pop = single_new_popsingle_new_pop = [];breakend    endx_next = x_insert;y_next = y_insert;max_iteration = max_iteration + 1;if max_iteration > 20000single_new_pop = [];breakendendif isempty(single_new_pop)breakend[~, single_path_num] = size(single_new_pop);i = i + 1;
end

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis(一)

1. Mybatis简介 MyBatis下载地址 1.1 MyBatis历史 MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下,iBatis3.x正式更名为MyBatis。代码于2013年11月迁移到Github…

Go语言的Json序列化与反序列化、Goto语法、Tcp Socket通信

目录标题 一、Json序列化与反序列化1. 序列化2. 反序列化 二、Goto语法三、Tcp Socket1. 单客户端发送信息到服务端2. 服务端客户端通信 一、Json序列化与反序列化 1. 序列化 package mainimport ("encoding/json""fmt")type Person struct {Name string…

【c趣编程】输入一个整数,判断其有几位

目录 1题目要求: 2解题思路: 3代码如下所示: 4运行代码如下: 5总结: 1题目要求: 只用一个scanf输出一串数,不可以一个一个的输入并计数,那样太浪费时间了。 C语言是一门面向过…

GoLong的学习之路(二十二)进阶,语法之并发(go最重要的特点)(channel的主要用法)

这一章是接上一章内容继续,上一章说到协程也就是goroutine,如何使用它,这一张是讲一种数据结构。当然这个章节的数据结构非常重要。可以说这个数据结构就是为了方便协程,才制作出来的。 单纯地将函数并发执行是没有意义的。函数与…

MySQL -- 用户管理

MySQL – 用户管理 文章目录 MySQL -- 用户管理一、用户1.用户信息2.创建用户3.删除用户4.远端登录MySQL5.修改用户密码6.数据库的权限 一、用户 1.用户信息 MySQL中的用户,都存储在系统数据库mysql的user表中: host: 表示这个用户可以从…

河南开放大学与电大搜题微信公众号:携手共进,助力学习之路

作为河南省内颇具影响力和声誉的高等教育机构之一,河南开放大学一直致力于提供优质的教育资源和灵活的学习方式,以满足广大学习者的需求。而在这个追求知识的时代,学习者们尤其需要一个便捷、高效的工具来辅助学习。电大搜题微信公众号应运而…

持续集成交付CICD:安装Gitlab Runner(从节点)

目录 一、实验 1.选择Gitlab Runner版本 2.安装Gitlab Runner(第一种方式:交互式安装) 3.安装Gitlab Runner(第二种方式:非交互式安装) 二、问题 1.如何查看Gitlab版本 一、实验 1.选择Gitlab Runne…

Web APIs——BOM和延迟函数setTimeout

1、window对象 1.1 BOM(浏览器对象模型) BOM(Browser Object Model)是浏览器对象模型 window对象是一个全局对象,也可以说是JavaScript中的顶级对象像document、alert()、console.log()这些都是window的属性&#xf…

windows11使用docker部署安装minio

时间 2023-11-08 windows11使用docker部署安装minio 目录 1.docker 下载镜像2.docker安装镜像3.访问控制台4.安装问题解决5.使用教程 1.docker 下载镜像 调整镜像源到国内,否则会很慢 docker pull minio/minio2.docker安装镜像 设置用户名和密码时需要注意&…

【好书推荐】计算机考研精炼1000题——考研408不可或缺

《计算机考研精炼1000题》简介 本书根据最新《全国硕士研究生招生考试计算机学科专业基础考试大纲》编写。参考过去十多年的真题,本书精心编排了单项选择题和综合应用题,共约1000道(分为上下两册,共24章。上册(1&#…

Spring基础(1):两个概念

最近看了点Spring的源码,于是来稍微扯一扯,希望能帮一部分培训班出身的朋友撕开一道口子,透透气。 广义上的Spring指的是Spring整个项目,包含SpringBoot、SpringCloud、SpringFramework、SpringData等等, 本系列文章…

sql学习

因为之前sql学的太烂了,想整理一下 一.什么是 SQL? SQL 是用于访问和处理数据库的标准的计算机语言。 SQL 指结构化查询语言SQL 使我们有能力访问数据库SQL 是一种 标准计算机语言 二.SQL 能做什么? SQL 面向数据库执行查询SQL 可从数据库…

17. 机器学习 - 随机森林

Hi,你好。我是茶桁。 我们之前那一节课讲了决策树,说了决策树的优点,也说了其缺点。 决策树实现起来比较简单,解释解释性也比较强。但是它唯一的问题就是不能拟合比较复杂的关系。 后来人们为了解决这个问题,让其能…

华为荣耀软开秋招面经问题整理

一、八股 1.linux常用命令 Linux常用命令(面试题)_linux常用命令面试题-CSDN博客 常用命令、系统命令、打包命令、vim、开关机命令 2.socket通信调用api过程 TCP UDP 3.进程和线程的区别 进程是系统进行资源分配和调度的基本单元,线程…

初阶JavaEE(15)(Cookie 和 Session、理解会话机制 (Session)、实现用户登录网页、上传文件网页、常用的代码片段)

接上次博客:初阶JavaEE(14)表白墙程序-CSDN博客 Cookie 和 Session 你还记得我们之前提到的Cookie吗? Cookie是HTTP请求header中的一个属性,是一种用于在浏览器和服务器之间持久存储数据的机制,允许网站…

【Linux】初识进程地址空间

❤️前言 大家好!这里是好久没有营业的大懒虫lion,今天要和大家聊的内容是我最近新学习的关于进程地址空间的相关知识。 正文 当我们使用C/C语言进行内存管理时,经常会接触到这样的一张图片: 它常常被我们称作程序地址空间&#…

Netty 是如何利用EventLoop实现千万级并发的

经过前面几篇文章的介绍,我们掌握了 Netty 的 5 个核心组件,但是有了这 5 个核心组件 Netty 这个工厂还是无法很好的运转,因为缺少了一个最核心的组件:EventLoop,它 是 Netty 中最最核心的组件,也是 Netty …

使用C++的QT框架实现五子棋

最近有点无聊正好想玩五子棋,那就实现一下这个游戏吧,网上的五子棋逻辑又长又复杂,我这个逻辑还是蛮简单的,展示如下(检测函数在最后) 这是一个简单的五子棋,今天就了解一下这个游戏的思路&…

机器学习——回归

目录 一、线性回归 1、回归的概念(Regression、Prediction) 2、符号约定 3、算法流程 4、最小二乘法(LSM) 二、梯度下降 梯度下降的三种形式 1、批量梯度下降(Batch Gradient Descent,BGD)&#xff…

【2023.11.6】OpenAI发布会——近期chatgpt被攻击,不能使用

OpenAI发布会 写在最前面发布会内容GPT-4 Turbo 具有 128K 上下文函数调用更新改进了指令遵循和 JSON 模式可重现的输出和对数概率更新了 GPT-3.5 Turbo 助手 API、检索和代码解释器API 中的新模式GPT-4 Turbo 带视觉DALLE 3文字转语音 (TTS)收听语音样本…