求解FJSP中的关键路径-附带Matlab源码


有任何关于车间调度的问题欢迎交流 [email protected]

关键路径在车间调度中的地位

在车间调度问题中,求解针对与问题特性或者目标函数特性的优化方法是高效优化的关键。而其中设计针对与问题特性的局部搜索算法尤为重要。而求解出调度序列中的关键路径是设计局部搜索的核心。

有两个特性
参考文章:Chao Lu, Energy-efficient Scheduling of Distributed Flow Shop with Heterogeneous Factories: A Real-world Case from Automobile Industry in China,2020,IEEE Transaction on industrial informatics.

特性1: 移动关键路径以外的工序可能会改变Makespan,但移动关键路径上的工序一定能改变Makespan。
证明: 关键路径表示调度序列构成的有向图中,从起始点到结束点消耗时间最长的节点构成的路径。即关键路径最后一个工序的完工时间就是makespan。 如果从关键路径上移动一个工序到非关键路径,则关键路径就会改变,则makespan就会改变。减少关键路径上工序的加工时间则会使得makespan减少。

调度序列转换为有向连通图

在这里插入图片描述
右边是一个甘特图,左边是甘特图转换的有向连通图。在FJSP问题中,工件的工序是可变的。而且针对与非完全柔性车间,所有工序可以选部分机器进行加工。

有向连通图的构成:每个工序是一个节点,或一个活动。每个活动有一个经历时间,也就是该工序在所选机器上的加工时间。在连通图的左边和右边分别有一个开始起点和结束终点。这两个点都是虚拟且必须存在的节点。这两个节点不存在于调度序列中。是便于计算而设定的。节点与节点之间的先序后序的关系,构成了有向边。边上没有活动和权重。权重只在节点处。连通图从上到下,每一行分别是每个工件的所有工序。按这样的排列位置或者拓扑位置。构成一个有向连通图。

柔性车间调度问题的有向连通图有一个最大的特性是:连通图中的每个节点除了工件第一工序和最后一个工序,有且仅有两个入度和两个出度。第一个工序只有一个入度,最后一个工序只有一个出度。

证明:每个工序有 O i , j O_{i,j} Oi,j有下一个工序 O i , j + 1 O_{i,j+1} Oi,j+1是可达的,还有处于同一台机器的,下一个即将被该机器 M k M_k Mk加工的工序是可达的。

关键路径求解算法

参考文章:https://blog.csdn.net/summer_dew/article/details/81607512

思路

在有向连通图中,从起点出发到每个节点为止,有多条路径是可达当前节点的。因此,从起点出发到当前节点,是要选经历时间最多的一条路径作为,到达当前节点的最大完工时间路径。

那么采用动态规划的思想。在一个拓扑有序的 序列 O , O 1 , 1 , O 2 , 1 , O 3 , 1 , O 1 , 2 , O 2 , 2 , O 3 , 2 , O 1 , 3 , O 2 , 3 , O 3 , 3 , E O,O_{1,1},O_{2,1},O_{3,1},O_{1,2},O_{2,2},O_{3,2},O_{1,3},O_{2,3},O_{3,3},E OO1,1O2,1O3,1O1,2O2,2O3,2O1,3O2,3O3,3E中。假设关键路径 C P ( O → E ) CP(O\rightarrow E) CP(OE) O , O 2 , 1 , O 1 , 1 , O 1 , 2 , O 2 , 3 , O 1 , 3 , O 3 , 3 , E O,O_{2,1},O_{1,1},O_{1,2},O_{2,3},O_{1,3},O_{3,3},E OO2,1O1,1O1,2O2,3O1,3O3,3E构成。那么递推公式就是 C P ( O → E ) = m a x { C P ( O → E l a s t ) + T i m e ( E l a s t → E ) } CP(O\rightarrow E)=max\{CP(O\rightarrow E_{last})+Time(E_{last}\rightarrow E)\} CP(OE)=max{ CP(OElast)+Time(ElastE)}

如果每一个节点的时间都是由前面所有可达的前序节点的时间决定。那么追根溯源,追溯到从起点开始的节点,就必须要遵循这个规则。

所以设定最早开始时间 V e ( t ) = V e ( O i , j ) = m a x { V e ( O i , j − 1 ) + p i , j − 1 , k , V e ( O i 1 , j 1 ) + p i 1 , j 1 , k } , ∀ t ∈ N Ve(t)=Ve(O_{i,j})=max\{Ve(O_{i,j-1})+p_{i,j-1,k},Ve(O_{i_1,j_1})+p_{i_1,j_1,k} \},\forall t\in N Ve(t)=Ve(Oi,j)=max{ Ve(Oi,j1)+pi,j1,k,Ve(Oi1,j1)+pi1,j1,k},tN N是节点集合, t是节点在集合中的下标索引, p i , j , k p_{i,j,k} pi,j,k是工序 O i , j O_{i,j} Oi,j在机器 M k M_k Mk上的加工时间, O i 1 , j 1 O_{i_1,j_1} Oi1,j1表示当前工序 O i , j O_{i,j} Oi,j在同一台机器上加工的前一个工序。

如果从前往后算可以算出最后一个节点的最大完工时间,那么从后往前算就可以算出开始节点的开始时间。相当于验算一遍,如果经过两次计算,得到的差值是最小的。那么说明该节点一定在关键路径中,因为差值小以为着浮动的时间小,是必须要先完成的任务。

设定最晚开始时间 V l ( t ) = V l ( O i , j ) = m i n { V l ( O i , j + 1 ) − p i , j , k , V l ( O i 2 , j 2 ) − p i , j , k } , ∀ t ∈ N Vl(t)=Vl(O_{i,j})=min\{Vl(O_{i,j+1})-p_{i,j,k},Vl(O_{i_2,j_2})-p_{i,j,k} \},\forall t\in N Vl(t)=Vl(Oi,j)=min{ Vl(Oi,j+1)pi,j,k,Vl(Oi2,j2)pi,j,k},tN O i 2 , j 2 O_{i_2,j_2} Oi2,j2表示当前工序 O i , j O_{i,j} Oi,j在同一台机器上加工的后一个工序。

关键路径求解算法

step1:从初始节点开始,计算所有节点的最早开始时间 V e Ve Ve, 初始节点 O O O V e = 0 Ve=0 Ve=0
step2: 从结束节点开始,计算所有节点的最晚开始时间 V l Vl Vl, 结束节点 E E E V l = V e Vl=Ve Vl=Ve
step3: 所有节点 d = V l − V e d=Vl-Ve d=VlVe, 找出所有节点中d最小的加入到关键路径中。
step4: 返回关键路径。

源代码-Matlab实现

数据结构设计

采用传统的双层编码结构,分别用两个数组存储工序顺序 p _ c h r o m p\_chrom p_chrom和机器选择 m _ c h r o m m\_chrom m_chrom
采用双向链表的方式,存储每个工序的 O i , j O_{i,j} Oi,j下一个工序 O i , j + 1 O_{i,j+1} Oi,j+1 p _ c h r o m p\_chrom p_chrom的索引号, O i , j O_{i,j} Oi,j在同一台机器上加工的后一个工序 O i 2 , j 2 O_{i_2,j_2} Oi2,j2 p _ c h r o m p\_chrom p_chrom的索引号, O i , j O_{i,j} Oi,j上一个工序 O i , j − 1 O_{i,j-1} Oi,j1 p _ c h r o m p\_chrom p_chrom的索引号, O i , j O_{i,j} Oi,j在同一台机器上加工的前一个工序 O i 1 , j 1 O_{i_1,j_1} Oi1,j1 p _ c h r o m p\_chrom p_chrom的索引号。

由于Matlab面向对象编程麻烦且鸡肋,于是在这里采用矩阵来记录每个工序的四个指针。指针就是在 p _ c h r o m p\_chrom p_chrom索引位置。
在这里插入图片描述

广度优先遍历

为了防止在计算每个节点时,后面的工序依赖于前一层的工序,如果前一层的还没算,后面的就算了,那么结果显然是错误的。于是采用广度优先遍历或者层序优先也行。广度优先遍历的顺序是,先算所有工件的第一个工序,再是所有工件的第二个工序。以此类推。

先从上到下,再从左到右。
在这里插入图片描述

递归遍历

如果出现比如说 当算到O33的Ve或者Vl时,O33的上一个工序的或者同一个机器的前置工序还没算出来Ve, 那么就需要递归调用一个求O33前置工序的函数取计算前置工序的Ve, 如果前置工序也没算,那么一直递归。直到递归到Oi1。 因为采用广度优先遍历Oi1肯定是第一批先被算了的。这样能保证不会出现无限递归。这是递归的终止条件。

function [value]=CalculateLastOperation(s1,s2,mm,digraph,last,VELTime,f_index)
global time;
    Index=last;
    e=0;
    t1=e;t2=e;
       if digraph(Index,3)~=0
           zlast=digraph(Index,3);
           if isempty(VELTime{
    
    zlast,1})               
               VELTime{
    
    zlast,1}=CalculateLastOperation(s1,s2,mm,digraph,zlast,VELTime,f_index);
           end
           t1=time{
    
    f_index,s1(zlast),s2(zlast),mm(zlast)}+VELTime{
    
    zlast,1};
       end
       
       if digraph(Index,4)~=0
           zlast=digraph(Index,4);
           if isempty(VELTime{
    
    zlast,1})              
               VELTime{
    
    zlast,1}=CalculateLastOperation(s1,s2,mm,digraph,zlast,VELTime,f_index);
           end
           t2=time{
    
    f_index,s1(zlast),s2(zlast),mm(zlast)}+VELTime{
    
    zlast,1};
       end     
       if t1>t2 %如果t1大于t2则
           VELTime{
    
    Index,1}=t1;
       else
           VELTime{
    
    Index,1}=t2;
       end
       value=VELTime{
    
    Index,1};
    
end
function [value]=CalculateNextOperation(s1,s2,mm,digraph,next,VELTime,LastNode,f_index)
global time;
    Index=next;
    e=0;
    t1=e;t2=e;
    if digraph(Index,1)==0
        t1=LastNode-time{
    
    f_index,s1(Index),s2(Index),mm(Index)};
    else
        znext=digraph(Index,1);
           if isempty(VELTime{
    
    znext,2})               
               VELTime{
    
    znext,2}=CalculateNextOperation(s1,s2,mm,digraph,znext,VELTime,LastNode,f_index);
           end
         t1=VELTime{
    
    znext,2}-time{
    
    f_index,s1(Index),s2(Index),mm(Index)};
    end
     
    if digraph(Index,2)==0
        t2=LastNode-time{
    
    f_index,s1(Index),s2(Index),mm(Index)};
    else      
           znext=digraph(Index,2);
           if isempty(VELTime{
    
    znext,2})              
               VELTime{
    
    znext,2}=CalculateNextOperation(s1,s2,mm,digraph,znext,VELTime,LastNode,f_index);
           end
           t2=VELTime{
    
    znext,2}-time{
    
    f_index,s1(Index),s2(Index),mm(Index)};
     end     
       if t1>t2 %如果t1大于t2则
           VELTime{
    
    Index,2}=t2;
       else
           VELTime{
    
    Index,2}=t1;
       end
       value=VELTime{
    
    Index,2};
    
end

源代码

function [CriticalPath,CriticalBlock,block]=FindCriticalPathDFJSP(p_chrom,m_chrom,FJ,f_index)
%将工序码构建成有向图的结构,有向图中包含节点集 即 所有工序
%包含边集,即两个节点之间是否含有有向边
%每个节点包含一个加工时间。每个工件的第一个工序作为开始节点的下一个节点。最多只有N个路径,N为工件个数。每个工序的最后一个工序作为结束节点的上一个工序。
%由于柔性车间调度的特殊性,导致有向图中每个节点只有两条出度两条入度。即当前工件的下一个工序,和当前机器的下一个工序。
%在这个有向图中求出,从开始节点到结束节点的最大完工时间的关键路径。
%采用的数据结构为数组加链表。数据用来存储每个工序的下标。每个数据元素后第一个元素为当前工件工序的下一个工序,第二个元素为当前机器工序的下一个工序。
%这两个元素都采用双向链表连接在数据的元素后面。实际为SH*4的矩阵。
%遍历每个工件的第一个工序,从第一个工序开始,广度遍历第二列求出一条路径,再深度遍历第三列求出一条路径。每条路径的结束标准都是,最后工序的下一列的值为0.

global N H time TM;

JOBN=length(FJ);
SH=length(p_chrom);
% drawFJSP(p_chrom,m_chrom,FJ);

%每一列分布表示 当前工件工序下一个工序的索引,当前工序所在机器的下一个工序索引,当前工序工件的上一个工序的索引,当前工序所在机器的上一个工序的索引
digraph=zeros(SH,4);%由于矩阵自身的行号本身就可以表示索引值,所以省略一列
dflag=zeros(SH,4);%用于标记该点是否找到
    %先 完成解码标记每个工序的工件和工序号
    s1=p_chrom;
    s2=zeros(1,SH);
    p=zeros(1,N);
    CriticalPath=[];%关键路径,其中包含关键工序的下标
    
    for i=1:SH
        p(s1(i))=p(s1(i))+1;%记录过程是否加工完成 完成一次加一
        s2(i)=p(s1(i));%记录加工过程中,工件的次数
    end
    
    for i=1:SH
        t1=s1(i);%记录到当前是那个工件
        t2=s2(i);%记录当前工件是加工到第几次
        mm(i)=m_chrom(1,sum(H(1,1:t1-1))+t2);%提取该工序该次加工的机器选择,因为机器码的排列表示该工件第几次加工所选的机器,是一段表示一个工件
    end
    %构建有向图
    for i=1:SH
        to=s1(i);tm=mm(i);
        %找当前工件工序的下一个工序
        
        for j=i+1:SH
            if to==s1(j)&&dflag(i,1)==0
                digraph(i,1)=j;
                dflag(i,1)=1; %下指针已经找到
                digraph(j,3)=i;
                dflag(j,3)=1;%上指针已经找到
            end
            %找当前机器工序的下一个工序
           if tm==mm(j)&&dflag(i,2)==0
                digraph(i,2)=j;
                dflag(i,2)=1;
                digraph(j,4)=i;
                dflag(j,4)=1;
           end
            %全部都找完跳出当前循环 或者如果当前工序当前工件的是最后一个工序
           if (dflag(i,1)==1||s2(i)==H(s1(i)))&&dflag(i,2)==1
               break;
           end
           
        end
    end
    VELTime=cell(SH,2);%每个工序的最早开始时间和最晚开始时间
    e=0;
    %采用广度遍历更新每个顶点的最早开始时间和最晚开始时间,如果不采用广度优先遍历,则会在更新后续层的时候,出现前序结点来不及计算,而导致计算错误。
    %广度优先遍历的顺序是,先算所有工件的第一个工序,再是所有工件的第二个工序。
    level=zeros(1,SH);
    len=1;L=1;
    while len<=SH
        for i=1:SH
            if s2(i)==L
                level(len)=i;
                len=len+1;
            end
        end
        L=L+1;
    end
    
    %计算最早开始时间
    LastNode=e;
    for i=1:SH
       Index=level(i);
       VELTime{
    
    Index,1}=e;%VELTime{
    
    Index,2}=e; 
       t1=e;t2=e;
       if digraph(Index,3)~=0
           last=digraph(Index,3);
           t1=time{
    
    f_index,s1(last),s2(last),mm(last)}+VELTime{
    
    last,1};
       end
       
       if digraph(Index,4)~=0
           last=digraph(Index,4);
           if isempty(VELTime{
    
    last,1})             
               VELTime{
    
    last,1}=CalculateLastOperation(s1,s2,mm,digraph,last,VELTime,f_index);
           end
           t2=time{
    
    f_index,s1(last),s2(last),mm(last)}+VELTime{
    
    last,1};
       end     
       if t1>t2 %如果t1大于t2则
           VELTime{
    
    Index,1}=t1;
       else
           VELTime{
    
    Index,1}=t2;
       end
       
       if digraph(Index,1)==0 %如果是工件的最后一个工序则说明下一个节点是LastNode虚拟结束节点, 则虚拟节点的上一个节点是所有工件的最后一个工序
           t1=time{
    
    f_index,s1(Index),s2(Index),mm(Index)}+VELTime{
    
    Index,1};%选最大的作为最后的虚拟节点
           if t1>LastNode
               LastNode=t1;
           end
       end
    end
    %计算最晚开始时间
    for i=SH:-1:1
        Index=level(i); 
%         fprintf('%s %d %s %d\r\n','O',s1(Index),'.',s2(Index));
        if digraph(Index,1)==0
            if digraph(Index,2)==0
                VELTime{
    
    Index,2}=LastNode-time{
    
    f_index,s1(Index),s2(Index),mm(Index)}; %最后一个拓扑有序的结点的工序的最晚开始时间等于最早开始时间             
            else
                t1=LastNode-time{
    
    f_index,s1(Index),s2(Index),mm(Index)};
                next=digraph(Index,2);
                if isempty(VELTime{
    
    next,2})
                    VELTime{
    
    next,2}=CalculateNextOperation(s1,s2,mm,digraph,next,VELTime,LastNode,f_index);
                end
                t2=VELTime{
    
    next,2}-time{
    
    f_index,s1(Index),s2(Index),mm(Index)};
                if t1>t2 %选最小的
                    VELTime{
    
    Index,2}=t2;
                else
                    VELTime{
    
    Index,2}=t1;
                end
            end
            continue;
        end
        
        t1=e;t2=e;
        if digraph(Index,1)~=0
           next=digraph(Index,1);
           t1=VELTime{
    
    next,2}-time{
    
    f_index,s1(Index),s2(Index),mm(Index)};%下一个节点减当前这条边的时间,但是时间在节点上所有减当前节点是时间
          if digraph(Index,2)==0
              VELTime{
    
    Index,2}=t1;
              continue;
          end
        end
%        
        if digraph(Index,2)~=0
           next=digraph(Index,2);
           if isempty(VELTime{
    
    next,2})
               VELTime{
    
    next,2}=CalculateNextOperation(s1,s2,mm,digraph,next,VELTime,LastNode,f_index);
           end
           t2=VELTime{
    
    next,2}-time{
    
    f_index,s1(Index),s2(Index),mm(Index)};
        end
       if t1>t2 %选最小的
           VELTime{
    
    Index,2}=t2;
       else
           VELTime{
    
    Index,2}=t1;
       end
%        if VELTime{
    
    Index,2}<0
%            fprintf('%s %d %s %d\r\n','O',s1(Index),'.',s2(Index));
%        end
    end
    
    %用最晚开始时间减最早开始时间,剩余时间最小的结点,则为关键路径上的结点。
    Idletime=cell(SH,1);
    for i=1:SH
        Idletime{
    
    i,1}=VELTime{
    
    i,2}-VELTime{
    
    i,1};
    end
    %找到松弛时间最小的工序则为关键路径上的工序
    MinIndex=1;
    MinIdleT=Idletime{
    
    1,1};
    for i=2:SH
        if MinIdleT>Idletime{
    
    i,1}
            MinIndex=i;
            MinIdleT=Idletime{
    
    i,1};
        end
    end
    for i=1:SH
        if MinIdleT==Idletime{
    
    i,1}
            CriticalPath=[CriticalPath,i];
        end
    end
    L=length(CriticalPath);
    block=1;
    CriticalBlock(block).B=[];%表示在同一个机器上具有前后关系的顺序的 工序
    CriticalBlock(block).B=[CriticalBlock(block).B,CriticalPath(1)];m0=mm(CriticalPath(1));
    for i=2:L
        m=mm(CriticalPath(i));
        if m0==m
            CriticalBlock(block).B=[CriticalBlock(block).B,CriticalPath(i)]; %在同一个机器上相邻的工序操作为一个邻接块
        else
            block=block+1;
            CriticalBlock(block).B=[];
            CriticalBlock(block).B=[CriticalBlock(block).B,CriticalPath(i)];
        end
        m0=m;
    end
end

function [value]=CalculateLastOperation(s1,s2,mm,digraph,last,VELTime,f_index)
global time;
    Index=last;
    e=0;
    t1=e;t2=e;
       if digraph(Index,3)~=0
           zlast=digraph(Index,3);
           if isempty(VELTime{
    
    zlast,1})               
               VELTime{
    
    zlast,1}=CalculateLastOperation(s1,s2,mm,digraph,zlast,VELTime,f_index);
           end
           t1=time{
    
    f_index,s1(zlast),s2(zlast),mm(zlast)}+VELTime{
    
    zlast,1};
       end
       
       if digraph(Index,4)~=0
           zlast=digraph(Index,4);
           if isempty(VELTime{
    
    zlast,1})              
               VELTime{
    
    zlast,1}=CalculateLastOperation(s1,s2,mm,digraph,zlast,VELTime,f_index);
           end
           t2=time{
    
    f_index,s1(zlast),s2(zlast),mm(zlast)}+VELTime{
    
    zlast,1};
       end     
       if t1>t2 %如果t1大于t2则
           VELTime{
    
    Index,1}=t1;
       else
           VELTime{
    
    Index,1}=t2;
       end
       value=VELTime{
    
    Index,1};
    
end

function [value]=CalculateNextOperation(s1,s2,mm,digraph,next,VELTime,LastNode,f_index)
global time;
    Index=next;
    e=0;
    t1=e;t2=e;
    if digraph(Index,1)==0
        t1=LastNode-time{
    
    f_index,s1(Index),s2(Index),mm(Index)};
    else
        znext=digraph(Index,1);
           if isempty(VELTime{
    
    znext,2})               
               VELTime{
    
    znext,2}=CalculateNextOperation(s1,s2,mm,digraph,znext,VELTime,LastNode,f_index);
           end
         t1=VELTime{
    
    znext,2}-time{
    
    f_index,s1(Index),s2(Index),mm(Index)};
    end
     
    if digraph(Index,2)==0
        t2=LastNode-time{
    
    f_index,s1(Index),s2(Index),mm(Index)};
    else      
           znext=digraph(Index,2);
           if isempty(VELTime{
    
    znext,2})              
               VELTime{
    
    znext,2}=CalculateNextOperation(s1,s2,mm,digraph,znext,VELTime,LastNode,f_index);
           end
           t2=VELTime{
    
    znext,2}-time{
    
    f_index,s1(Index),s2(Index),mm(Index)};
     end     
       if t1>t2 %如果t1大于t2则
           VELTime{
    
    Index,2}=t2;
       else
           VELTime{
    
    Index,2}=t1;
       end
       value=VELTime{
    
    Index,2};
    
end

甘特图

在这里插入图片描述

测试用例

p-chrom

11	18	20	13	5	3	17	19	12	7	1	14	6	15	8	2	4	16	9	10	8	6	3	15	4	3	18	14	7	17	5	15	10	18	14	5	10	20	6	8	18	16	12	19	13	9	17	20	12	1	11	13	3	19	8	9	10	18	16	2	12	17	9	11	2	14	6	19	13	3	20	2	13	1	13	11	19	7	18	6	7	5	14	12	8	15	1	12	2	5	14	20	4	15	1	10

m-chrom

2	1	5	4	5	4	1	2	1	5	6	6	1	5	5	6	2	4	3	6	3	5	4	3	4	6	6	3	5	3	2	6	1	3	2	6	1	1	1	6	5	2	4	5	2	6	5	3	3	6	3	2	5	4	2	2	2	6	4	3	4	1	4	6	2	4	4	6	2	5	2	6	3	5	1	6	1	5	3	1	1	4	1	5	3	1	6	4	3	6	3	4	4	2	2	1

原始文件 Type2FJSP-20-6
下载链接http://ischedulings.com/shares.html 山东师范李俊青教授

20 6
0 1041 5
19 21 24 27 30 10 11 13 14 15 0 0 0 0 0 12 14 16 18 19 20 23 26 28 32 8 9 10 11 14 
24 27 30 33 38 17 19 22 25 28 0 0 0 0 0 24 27 31 35 37 24 27 31 34 39 10 11 13 14 16 
15 17 19 21 24 22 25 28 30 35 0 0 0 0 0 14 16 18 19 21 17 19 22 25 26 20 23 26 29 32 
0 0 0 0 0 20 22 25 27 30 26 29 33 37 41 8 9 10 12 12 20 22 25 27 32 21 24 27 29 32 
18 20 23 25 29 0 0 0 0 0 14 16 18 20 21 20 23 26 29 33 11 12 14 15 16 8 9 11 13 14 
1 2658 5
25 28 32 35 38 9 10 12 14 16 27 30 34 37 41 16 18 21 24 27 11 12 14 16 18 0 0 0 0 0 
13 15 17 19 20 9 10 12 13 16 12 13 15 17 19 12 13 15 17 18 20 23 26 28 32 0 0 0 0 0 
12 14 16 18 20 22 25 28 31 33 15 17 19 21 24 0 0 0 0 0 18 20 23 25 29 17 19 22 24 28 
8 9 10 11 13 24 27 30 33 36 0 0 0 0 0 22 25 28 31 34 24 27 31 35 37 27 30 34 37 41 
18 20 23 26 28 8 9 10 12 14 26 29 33 37 40 24 27 31 35 37 21 24 27 30 34 0 0 0 0 0 
2 1519 5
0 0 0 0 0 10 11 13 14 17 22 25 28 31 33 17 19 22 25 27 23 26 29 32 36 9 10 12 14 14 
19 21 24 27 30 24 27 31 35 39 13 15 17 18 20 11 12 14 16 17 0 0 0 0 0 18 20 23 25 28 
24 27 31 34 38 0 0 0 0 0 8 9 10 12 14 16 18 21 23 27 25 28 32 35 38 21 24 27 29 32 
18 20 23 26 27 17 19 22 24 28 0 0 0 0 0 21 24 27 30 34 27 30 34 37 42 10 11 13 15 16 
16 18 20 22 25 0 0 0 0 0 24 27 31 34 39 21 24 27 29 32 11 12 14 15 17 13 15 17 18 22 
3 2512 3
26 29 33 36 40 17 19 22 25 26 17 19 22 25 27 22 25 28 31 35 0 0 0 0 0 22 25 28 31 33 
12 13 15 17 18 17 19 22 24 28 16 18 21 24 27 12 13 15 16 18 0 0 0 0 0 8 9 11 13 15 
8 9 10 11 13 23 26 29 31 34 0 0 0 0 0 11 12 14 16 17 23 26 29 31 36 24 27 31 35 38 
4 1745 5
9 10 12 14 15 0 0 0 0 0 12 13 15 17 18 22 25 28 31 35 19 21 24 26 30 18 20 23 25 28 
12 13 15 17 20 0 0 0 0 0 24 27 30 34 38 21 24 27 29 34 22 25 28 31 35 24 27 30 33 38 
21 24 27 29 34 13 15 17 19 20 27 30 34 37 41 0 0 0 0 0 16 18 21 24 25 8 9 10 11 14 
16 18 20 22 25 16 18 20 23 26 0 0 0 0 0 27 30 34 37 42 23 26 29 31 35 16 18 20 23 26 
0 0 0 0 0 9 10 12 13 15 23 26 29 31 35 15 17 19 20 23 10 11 13 15 15 17 19 22 24 27 
5 1227 5
9 10 12 13 15 0 0 0 0 0 26 29 33 36 41 9 10 12 14 16 16 18 21 24 25 19 21 24 26 28 
10 11 13 14 16 0 0 0 0 0 12 13 15 17 19 24 27 31 35 37 16 18 20 22 25 24 27 30 33 38 
8 9 10 12 12 0 0 0 0 0 18 20 23 25 28 10 11 13 15 16 20 22 25 28 32 17 19 22 24 28 
11 12 14 15 17 25 28 32 36 39 8 9 11 12 15 0 0 0 0 0 10 11 13 14 15 12 13 15 17 18 
8 9 11 13 14 17 19 22 24 26 24 27 31 35 38 24 27 31 35 39 0 0 0 0 0 16 18 20 23 26 
6 1296 4
0 0 0 0 0 11 12 14 16 17 16 18 20 22 26 13 15 17 19 22 23 26 29 32 36 17 19 22 24 28 
0 0 0 0 0 12 13 15 16 19 24 27 30 33 36 15 17 19 21 24 26 29 33 37 40 16 18 21 24 26 
0 0 0 0 0 22 25 28 31 33 8 9 10 12 13 17 19 22 25 28 17 19 22 25 26 12 13 15 16 18 
26 29 33 37 41 17 19 22 25 28 8 9 10 11 14 16 18 20 22 24 0 0 0 0 0 12 14 16 17 19 
7 2145 5
12 14 16 18 19 0 0 0 0 0 21 24 27 29 32 8 9 11 12 14 14 16 18 20 23 8 9 10 11 13 
14 16 18 19 23 20 22 25 27 30 27 30 34 37 40 8 9 11 13 15 0 0 0 0 0 21 24 27 30 32 
24 27 30 34 38 8 9 10 11 12 18 20 23 26 27 0 0 0 0 0 16 18 20 23 25 11 12 14 16 18 
15 17 19 21 23 20 23 26 28 33 0 0 0 0 0 25 28 32 36 40 13 15 17 19 20 8 9 10 12 12 
20 22 25 27 31 0 0 0 0 0 22 25 28 31 33 19 21 24 27 30 24 27 31 35 37 17 19 22 25 28 
8 1570 4
25 28 32 36 38 20 22 25 28 31 0 0 0 0 0 10 11 13 15 17 8 9 10 12 14 17 19 22 25 28 
20 22 25 28 32 0 0 0 0 0 16 18 20 22 26 21 24 27 30 32 11 12 14 15 18 12 13 15 16 18 
0 0 0 0 0 20 23 26 29 31 26 29 33 37 41 11 12 14 15 17 22 25 28 31 35 8 9 10 12 12 
0 0 0 0 0 12 13 15 16 19 21 24 27 30 34 21 24 27 29 34 26 29 33 36 39 25 28 32 35 40 
9 2141 5
18 20 23 26 28 20 22 25 27 30 20 23 26 29 31 0 0 0 0 0 12 14 16 17 20 17 19 22 24 27 
12 14 16 17 20 10 11 13 15 17 20 23 26 28 31 21 24 27 30 33 0 0 0 0 0 17 19 22 24 26 
19 21 24 26 30 0 0 0 0 0 22 25 28 30 35 16 18 21 23 26 8 9 10 12 14 13 15 17 18 20 
0 0 0 0 0 26 29 33 36 39 21 24 27 30 32 24 27 30 33 37 10 11 13 14 15 23 26 29 32 35 
17 19 22 24 26 22 25 28 31 33 0 0 0 0 0 8 9 10 11 12 14 16 18 20 22 21 24 27 30 32 
10 1082 4
20 23 26 29 32 16 18 20 23 26 12 13 15 17 19 18 20 23 25 28 16 18 20 22 25 0 0 0 0 0 
0 0 0 0 0 20 22 25 28 31 8 9 10 12 13 10 11 13 14 17 21 24 27 30 34 27 30 34 38 40 
27 30 34 37 40 26 29 33 37 39 12 13 15 16 18 0 0 0 0 0 11 12 14 16 17 16 18 21 23 27 
0 0 0 0 0 24 27 31 35 38 9 10 12 13 16 20 23 26 28 31 19 21 24 26 30 19 21 24 27 30 
11 2602 6
0 0 0 0 0 11 12 14 15 17 12 13 15 17 18 15 17 19 20 22 12 14 16 17 20 22 25 28 30 35 
11 12 14 15 18 26 29 33 36 39 19 21 24 26 30 15 17 19 20 24 0 0 0 0 0 23 26 29 31 34 
10 11 13 14 15 9 10 12 13 14 24 27 31 35 39 0 0 0 0 0 12 13 15 16 18 8 9 10 11 12 
25 28 32 36 40 10 11 13 14 15 14 16 18 19 22 12 13 15 17 18 17 19 22 24 26 0 0 0 0 0 
0 0 0 0 0 11 12 14 15 16 8 9 10 12 12 19 21 24 26 28 8 9 10 12 14 23 26 29 32 35 
17 19 22 24 27 27 30 34 37 40 26 29 33 37 39 8 9 10 12 14 0 0 0 0 0 12 13 15 17 20 
12 1714 6
14 16 18 20 22 16 18 20 23 26 27 30 34 38 41 17 19 22 25 28 0 0 0 0 0 26 29 33 36 41 
23 26 29 32 34 16 18 20 22 25 16 18 21 24 25 0 0 0 0 0 27 30 34 38 40 25 28 32 35 38 
0 0 0 0 0 16 18 21 23 27 8 9 11 12 14 27 30 34 37 40 14 16 18 19 21 24 27 30 34 36 
25 28 32 36 39 27 30 34 37 42 25 28 32 35 39 20 23 26 28 31 12 13 15 16 20 0 0 0 0 0 
25 28 32 35 38 11 12 14 15 16 17 19 22 25 26 26 29 33 36 41 14 16 18 19 23 0 0 0 0 0 
12 14 16 17 19 21 24 27 30 33 25 28 32 35 38 25 28 32 36 40 0 0 0 0 0 13 15 17 18 21 
13 1776 6
13 15 17 18 20 0 0 0 0 0 8 9 10 11 13 15 17 19 20 24 9 10 12 14 14 22 25 28 30 34 
25 28 32 36 40 17 19 22 25 27 0 0 0 0 0 14 16 18 19 21 9 10 12 14 16 8 9 11 12 13 
9 10 12 13 16 12 13 15 16 19 21 24 27 30 33 0 0 0 0 0 15 17 19 20 24 23 26 29 32 34 
14 16 18 20 21 21 24 27 29 34 17 19 22 25 27 24 27 30 34 38 0 0 0 0 0 24 27 30 34 36 
22 25 28 31 35 20 22 25 28 30 0 0 0 0 0 13 15 17 18 21 21 24 27 29 32 10 11 13 15 17 
10 11 13 15 17 0 0 0 0 0 13 15 17 19 21 16 18 20 22 25 16 18 20 23 26 16 18 21 24 25 
14 2837 5
0 0 0 0 0 16 18 20 22 26 10 11 13 15 15 23 26 29 31 36 9 10 12 13 15 25 28 32 36 40 
10 11 13 14 16 26 29 33 37 40 8 9 10 11 12 25 28 32 35 40 27 30 34 38 41 0 0 0 0 0 
9 10 12 13 14 15 17 19 21 23 16 18 20 22 25 18 20 23 26 28 12 13 15 16 18 0 0 0 0 0 
10 11 13 14 17 0 0 0 0 0 24 27 30 33 38 19 21 24 27 28 8 9 11 12 15 9 10 12 14 15 
23 26 29 31 34 20 22 25 28 32 24 27 30 33 36 27 30 34 38 40 0 0 0 0 0 14 16 18 20 21 
15 1813 3
27 30 34 37 40 26 29 33 37 41 16 18 20 22 26 0 0 0 0 0 15 17 19 21 23 12 14 16 18 19 
11 12 14 16 18 0 0 0 0 0 20 23 26 28 31 8 9 10 12 12 12 14 16 17 20 24 27 31 34 38 
0 0 0 0 0 26 29 33 36 39 22 25 28 31 33 22 25 28 30 33 8 9 11 12 13 22 25 28 30 34 
16 2874 4
16 18 21 24 26 20 23 26 29 33 8 9 11 13 14 13 15 17 18 20 17 19 22 25 27 0 0 0 0 0 
20 22 25 28 32 0 0 0 0 0 19 21 24 27 28 20 22 25 28 30 24 27 30 34 38 10 11 13 14 15 
12 13 15 17 20 20 23 26 29 32 13 15 17 19 21 0 0 0 0 0 18 20 23 26 28 25 28 32 35 39 
26 29 33 37 41 12 14 16 18 19 16 18 20 23 24 25 28 32 35 38 0 0 0 0 0 12 13 15 16 18 
17 1281 6
10 11 13 15 16 22 25 28 31 34 25 28 32 35 39 16 18 20 22 24 0 0 0 0 0 15 17 19 20 24 
8 9 10 12 14 27 30 34 38 42 24 27 30 33 38 8 9 10 12 14 20 23 26 29 32 0 0 0 0 0 
25 28 32 36 38 19 21 24 27 30 17 19 22 25 26 25 28 32 36 39 0 0 0 0 0 12 13 15 16 20 
18 20 23 25 28 20 23 26 29 31 0 0 0 0 0 23 26 29 32 35 24 27 30 34 36 26 29 33 37 40 
20 22 25 28 31 10 11 13 14 16 20 22 25 27 31 16 18 20 23 25 0 0 0 0 0 16 18 21 23 27 
9 10 12 14 14 9 10 12 13 15 0 0 0 0 0 16 18 21 24 25 16 18 21 23 27 22 25 28 31 34 
18 1542 5
13 15 17 19 22 0 0 0 0 0 18 20 23 26 29 15 17 19 21 23 22 25 28 31 33 25 28 32 36 39 
18 20 23 26 28 0 0 0 0 0 24 27 31 35 38 25 28 32 35 38 12 13 15 17 18 22 25 28 30 33 
14 16 18 20 22 8 9 11 13 15 15 17 19 20 23 24 27 30 33 36 0 0 0 0 0 24 27 30 33 38 
25 28 32 35 40 12 13 15 16 18 0 0 0 0 0 8 9 10 12 13 13 15 17 18 20 17 19 22 24 28 
20 23 26 29 33 0 0 0 0 0 16 18 20 22 26 26 29 33 36 41 13 15 17 18 22 22 25 28 30 34 
19 1762 5
23 26 29 32 35 21 24 27 29 32 24 27 31 34 37 20 22 25 28 32 26 29 33 36 41 0 0 0 0 0 
14 16 18 19 23 10 11 13 15 15 0 0 0 0 0 17 19 22 25 27 22 25 28 31 34 16 18 21 23 27 
24 27 31 35 39 20 22 25 27 32 26 29 33 37 39 12 13 15 16 20 0 0 0 0 0 17 19 22 24 28 
11 12 14 15 18 16 18 20 22 24 0 0 0 0 0 11 12 14 15 16 17 19 22 25 28 14 16 18 20 21 
24 27 30 33 37 24 27 31 34 39 8 9 11 12 15 18 20 23 25 28 0 0 0 0 0 18 20 23 25 27 
0 1271 183 121 73 
1 1221 185 41 55 
2 1110 115 161 32 
3 1312 171 35 65 
4 1393 158 99 92 
5 1108 74 42 17 
17 50 8000 20000 0.52 0.78 30 5000 750 12500 0.43 0.49 900 10000 9746 5493 21 2.062

猜你喜欢

转载自blog.csdn.net/qq_36820823/article/details/121919799