c++搜索剪枝常见方法与技巧

目录

      

            搜索剪枝常见方法与技巧

关键字  搜索方法,剪枝

摘要

正文

  小结

程序

参考书目


      

            搜索剪枝常见方法与技巧

关键字  搜索方法,剪枝

摘要

搜索是计算机解题中常用的方法,它实质上是枚举法的应用。由于它相当于枚举法,所以其效率是相当地的。因此,为了提高搜索的效率,人们想出了很多剪枝的方法,如分枝定界,启发式搜索等等。在竞赛中,我们不仅要熟练掌握这些方法,而且要因地制宜地运用一些技巧,以提高搜索的效率。

正文

搜索的效率是很低的,即使剪枝再好,也无法弥补其在时间复杂度上的缺陷。因此,在解题中,除非其他任何方法都行不通,才可采用搜索。

既然采用了搜索,剪枝就显得十分的必要,即使就简简单单的设一个槛值,或多加一两条判断,就可对搜索的效率产生惊人的影响。例如N后问题,假如放完皇后再判断,则仅仅只算到7,就开始有停顿,到了8就已经超过了20秒,而如果边放边判断,就算到了10,也没有停顿的感觉。所以,用搜索就一定要剪枝。

剪枝至少有两方面,一是从方法上剪枝,如采用分枝定界,启发式搜索等,适用范围比较广;二是使用一些小技巧,这类方法适用性虽不如第一类,有时甚至只能适用一道题,但也十分有效,并且几乎每道题都存在一些这样那样的剪枝技巧,只是每题有所不同而已。

问题一:(最短编号序列)

表A和表B各含k(k<=20)个元素,元素编号从1到k。两个表中的每个元素都是由0和1组成的字符串。(不是空格)字符串的长度<=20。例如下表的A和B两个表,每个表都含3个元素(k=3)。

    元素编号

     字符串

       1

      1

       2

      10111

       3

      10

表A 表B

    元素编号

     字符串

       1

      111

       2

      10

       3

      0

对于表A和表B,存在一个元素编号的序列2113,分别用表A中的字符串和表B 中的字符串去置换相应的元素编号,可得相同的字符串序列101111110,见下表。

  元素编号序列

    2

    1

    1

    3

  用表A的字符串替换

   10111

    1

    1

    10

  用表B的字符串替换

    10

   111

   111

    0

对表A和表B,具有上述性质的元素编号序列称之为S(AB)。对于上例S(AB)=2113。

编写程序:从文件中读入表A和表B的各个元素,寻找一个长度最短的具有上述性质的元素编号序列S(AB)。(若找不到长度<=100的编号序列,则输出“No Answer”。

对于这道题,因为表A和表B不确定,所以不可能找到一种数学的方法。因为所求的是最优解,而深度优先搜索很容易进入一条死胡同而浪费时间,所以必须采用广度优先搜索的方法。但是,广度优先搜索也有其缺陷。当表A和表B中的元素过多是,扩展的结点也是相当多的,搜索所耗费的时间也无法达到测试的要求。为了解决这个问题,就必须对搜索的算法加以改进。分枝限界似乎不行,因为无法确定代价。而且,由于目标不确定,也无法设定估价函数。但是,因为此题的规则既可以正向使用,又可以逆向使用,于是便可以采用双向搜索。

在大方法确定后,算法的框架就已经基本形成,但即使如此,算法也还有可改进的地方。

  1. 存储当前的A串和B串是很费空间的,但因为A串和B串的大部分相同,故只需记录不同部分,并作个标记。再换成动态存储。
  2. 为了保证两个方向扩展结点的速度相对平衡,可以采取每次扩展结点数较少的方向,而不是两方向轮流扩展。

如此一来,搜索的效率就比单纯的广度优先搜索有了明显的提高。

(附程序sab.pas)

有时,搜索也会有不同的搜索方法(如多处理机调度问题),也会产生不同的效率。

问题二:(任务安排)

N个城市,若干城市间有道路相连,一辆汽车在城市间运送货物,总是从城市1出发,又回到城市1。该车每次需完成若干个任务,每个任务都是要求该车将货物从一个城市运送至另一个。例如若要完成任务2->6,则该车一次旅程中必含有一条子路径。先到2,再到6。

如下图所示,如果要求的任务是2->3,2->4,3->1,2->5,6->4,则一条完成全部任务的路径是1->2->3->1->2->5->6->4->1。

 4

1   2    6

  5

  3 7

    编程由文件读入道路分布的领接矩阵,然后对要求完成的若干任务,寻找一条旅行路线,使得在完成任务最多的前提下,经过的城市总次数最少。如上例中经过城市总次数为8,城市1和2各经过2次均以2次计(起点不计),N<60。

这道题,因为很难找到数学规律,便只有采用搜索的方法。

首先,第一感觉便是:从城市i出发,便搜索所有相邻的城市,再根据当前所处的城市,确定任务的完成情况,从中找到最优解。这种搜索的效率是极低的,其最大原因就在于:目标不明确。

根据题意,我们只需到达需上货和下货的城市,其它的城市仅作为中间过程,而不应作为目标。因此,首先必须确定可能和不可能完成的任务,然后求出任意两城市间的最短路径。在搜索时,就只需考虑有货要上的城市,或者是要运到该城市的货全在车上,其它不须考虑。同时,还可以设定两个简单的槛值。如果当前费用+还需达的城市>=当前最优解,或当前费用+返回城市1的费用>=当前最优解,则不需继续往下搜索。

这种方法与第一感的方法有天壤之别。(附程序travell.pas)

问题三:(多处理机调度问题)

设定有若干台相同的处理机P1,P2      Pn,和m个独立的作业J1,J2      jm,处理机以互不相关的方式处理作业,现约定任何作业可以在任何一台处理机上运行,但未完工之前不允许中断作业,作业也不能拆分成更小的作业,已知作业Ji需要处理机处理的时间为Ti(i=1,2      m)。编程完成以下两个任务:

任务一:假设有n台处理机和m个作业及其每一个作业所需处理的时间Ti存放在文件中,求解一个最佳调度方案,使得完成这m个作业的总工时最少并输出最少工时。

任务二:假设给定作业时间表和限定完工时间T于文件中,求解在限定时间T内完成这批作业所需要最少处理机台数和调度方案。

此题有两种搜索方法:

方法一:按顺序搜索每个作业。当搜索一个作业时,将其放在每台处理机搜索一次。

方法二:按顺序搜索每台处理机。当搜索一台处理机时,将每个作业放在上面搜索一次。

对比上述两种方法,可以发现:方法二较方法一更容易剪枝。

下面是两中方法剪枝的对照:

对于方法一:只能根据目前已确定的需时最长的处理机的耗时与目前最佳解比较。

对于方法二:可约定Time[1]>Time[2]>Time[3]>       >Time[n](Time[i]表示第i台处理机的处理时间),从而可以设定槛值:如当前处理机的处理时间>=目前最佳解,或剩下的处理机台数×上一台处理机的处理时间<剩余的作业需要的处理时间,则回溯。因为在前面的约束条件下,已经不可能有解。

    因此,从上面的比较来看,第二种方法显然是比第一种要好的。下面就针对第二种方法更深一层的进行探讨。

   对于任务一,首先可以用贪心求出Time[1]的上界。然后,还可以Time[1]的下界,UP(作业总时间/处理机台数)。(UP表示大于等于该小数的最小整数)。搜索便从上界开始,找到一个解后,若等于下界即可停止搜索。

(附程序jobs_1.pas)

    对于任务二,可采用深度+可变下界。下界为:UP(作业总时间/限定时间),即至少需要的处理机台数。并设定Time[1]的上界为T。

(附程序jobs_2.pas)

  小结

搜索的使用相当广泛,几乎每题都可以采用搜索的方法。虽然如此,搜索也切不可滥用。只有当问题无规律可寻时,才可用搜索。一旦确定了使用搜索,就一定要想办法对其进行剪枝。无论是采用剪枝的常见方法,还是用一些搜索的小技巧,虽都无法降低搜索的时间复杂度,却总还是大有裨益的。

程序

1. 最短编号序列:sab.pas

program sab;

type aa=string[100];

     ltype=record

                 f:integer;  {父指针}

                 k,d,la,lb:shortint;

   {k--剩余串标志,d--序列中元素的编号,la,lb--A,B两串的串长}

                 st:^aa;  {剩余串}

     end;

const maxn=1300;

var t,h:array[0..1] of integer;  {h--队首指针,t--队尾指针,0表示正向,1表示逆向}

    p:array[0..1,1..maxn] of ltype;  {p[0]--正向搜索表,p[1]--逆向搜索表}

    strs:array[1..2,1..20] of string[20];  {strs[1]--表A元素,strs[2]--表B元素}

    n:integer;   {表A和表B的元素个数}

procedure readp;  {读入数据}

var f:text;

    st:string;

    i,j:integer;

begin

     write('File name:');

     readln(st);

     assign(f,st);

     reset(f);

     readln(f,n);

     for i:=1 to n do

         readln(f,strs[1,i]);

     for i:=1 to n do

         readln(f,strs[2,i]);

     close(f);

end;

procedure print(q,k:integer);  {从k出发,输出沿q方向搜索的元素编号}

begin

     if k<>1 then begin

        if q=1 then

           writeln(p[q,k].d);

        print(q,p[q,k].f);

        if q=0 then

           writeln(p[q,k].d);

     end;

end;

procedure check(q:shortint);  {判断两方向是否重合,q表示刚产生结点的方向的相反方向}

var i:integer;

begin

     for i:=1 to t[1-q]-1 do

         if (p[q,t[q]].k<>p[1-q,i].k) and (p[q,t[q]].st^=p[1-q,i].st^) and

            (p[q,t[q]].la+p[1-q,i].la<=100) and (p[q,t[q]].lb+p[1-q,i].lb<=100)

            then begin

                      if q=0 then

                         begin

                              print(0,t[q]);

                              print(1,i);

                         end

                      else begin

                                print(0,i);

                                print(1,t[q]);

                           end;

                      halt;

            end;

end;

procedure find(q:shortint); {沿q方向扩展一层结点}

var i:integer;

    sa,sb:aa;

begin

     for i:=1 to n do

         if (p[q,h[q]].la+length(strs[1,i])<=100) and

            (p[q,h[q]].lb+length(strs[2,i])<=100) then

            begin

                 sa:='';sb:='';

                 if p[q,h[q]].k=1

                    then sa:=p[q,h[q]].st^

                    else sb:=p[q,h[q]].st^;

                 if q=0 then  {沿不同方向将编号为i的元素加到序列中}

                    begin

                         sa:=sa+strs[1,i];

                         sb:=sb+strs[2,i];

                         while (sa<>'') and (sb<>'') and (sa[1]=sb[1]) do

                               begin

                                    delete(sa,1,1);

                                    delete(sb,1,1);

                               end

                    end

                 else begin

                           sa:=strs[1,i]+sa;sb:=strs[2,i]+sb;

                           while (sa<>'') and (sb<>'') and

                                 (sa[length(sa)]=sb[length(sb)]) do

                                 begin

                                      delete(sa,length(sa),1);

                                      delete(sb,length(sb),1);

                                 end;

                      end;

                 if (sa='') or (sb='') then  {生成一个新的结点}

                    with p[q,t[q]] do

                         begin

                              f:=h[q];d:=i;

                              la:=p[q,h[q]].la+length(strs[1,i]);

                              lb:=p[q,h[q]].lb+length(strs[2,i]);

                              new(st);

                              if sa='' then

                                 begin

                                      k:=2;st^:=sb

                                 end

                              else begin

                                        k:=1;st^:=sa;

                                   end;

                              check(q);

                              inc(t[q]);

                         end;

            end;

     inc(h[q]);

end;

begin

     readp;

     h[0]:=1;h[1]:=1;

     t[0]:=2;t[1]:=2;

     new(p[0,1].st);p[0,1].st^:='';

     new(p[1,1].st);p[1,1].st^:='';

     {队列初始化}

     while (h[0]<t[0]) and (h[1]<t[1]) and (t[0]<maxn) and (t[1]<maxn) do

           if t[0]<t[1]  {比较两方向的节点数,向结点数少的方向扩展}

              then find(0)

              else find(1);

     writeln('No answer!');

end.

  1. 任务安排:travell.pas

program travell;

var path,  {path[i,j]--以i为起点第j个运输终点}

    next,  {next[i,j]--从i到j的最短路径中,i顶点的下一个顶点}

    dist,  {dist[i,j]--从i到j的最短路径长度}

    road:array[1..60,1..60] of integer;  {道路的邻接矩阵}

    head,  {head[i]--以i为起点的任务数}

tail,  {tail[i]--0表示以i为终点无任务或已完成}

   {1表示以i为终点的任务的所有顶点都在完成任务路径中}

   {k+1表示以i为终点的所有任务,还有k个顶点未到达}

    arrive:array[1..60] of integer;  {arrive[i]--顶点i的经过次数}

    d,  {完成任务路径}

    bestd:array[1..100] of integer;  {当前最佳完成任务路径}

    left,  {必经结点个数}

    cost,  {当前代价}

    mincost,  {最佳完成任务代价}

    s,  {经过顶点数}

    bests,  {最佳完成任务所经过的顶点数}

    m,  {任务数}

    n:integer;  {城市数}

procedure findshortest;  {求任意两点间的最短路径}

var i,j,k:integer;

begin

     for i:=1 to n do

         for j:=1 to n do

             if road[i,j]=1 then

                begin

                     dist[i,j]:=1;

                     next[i,j]:=j

                end

             else dist[i,j]:=100;

     for k:=1 to n do

         for i:=1 to n do

             for j:=1 to n do

                 if dist[i,k]+dist[k,j]<dist[i,j] then

                    begin

                         dist[i,j]:=dist[i,k]+dist[k,j];

                         next[i,j]:=next[i,k];

                    end;

end;

procedure init;  {读入数据并初始化数据}

var i,j,k:integer;

    st:string;

    f:text;

begin

     write('File name:');

     readln(st);

     assign(f,st);

     reset(f);

     readln(f,n);

     for i:=1 to n do

         for j:=1 to n do

             read(f,road[i,j]);

     findshortest;

     readln(f,m);

     for i:=1 to m do

         begin

              read(f,j,k);

              if (dist[1,j]<100) and (dist[1,k]<100) then

                 begin

                      inc(head[j]);

                      inc(tail[k]);

                      path[j,head[j]]:=k;

                 end;

         end;

     close(f);

     for i:=1 to m do

         if tail[i]>0 then

            inc(tail[i]);

     for i:=1 to head[1] do

         dec(tail[path[1,i]]);

     head[1]:=0;inc(s);d[s]:=1;left:=0;

     cost:=0;mincost:=maxint;

     for i:=2 to n do

         if (head[i]>0) or (tail[i]>0) then

            inc(left);

end;

procedure try;  {搜索过程}

var i,j,k:integer;

    p:boolean;

begin

     if (cost+left>=mincost) or (cost+dist[1,d[s]]>=mincost) then exit;

     if left=0 then  {是否完成了所有任务}

        begin

             mincost:=cost+dist[1,d[s]];

             bestd:=d;

             bests:=s;

             inc(bests);bestd[bests]:=1;

             exit;

        end;

     for i:=2 to n do

         if (head[i]>0) or (tail[i]=1) then  {如果去i顶点有必要}

            begin

                 inc(cost,dist[d[s],i]);

                 inc(arrive[i]);

                 inc(s);

                 d[s]:=i;

                 if arrive[i]=1 then  

{如果i顶点第一次到达,则所有以i为起点的任务的终点tail值减1}

                    for j:=1 to head[i] do

                        dec(tail[path[i,j]]);

                 k:=head[i];

                 head[i]:=0;

                 if tail[i]=1 then  

 {如果完成了以i为终点的所有任务,该点则不需再经过}

                    begin

                         p:=true;

                         dec(tail[i]);

                    end

                    else p:=false;

                 if tail[i]=0 then  

                    dec(left);

                 try;

   {恢复递归前的数据}

                 if tail[i]=0 then

                    inc(left);

                 if true then

                    inc(tail[i]);

                 head[i]:=k;

                 if arrive[i]=1 then

                    for j:=1 to head[i] do

                        inc(tail[path[i,j]]);

                 dec(s);

                 dec(arrive[i]);

                 dec(cost,dist[d[s],i]);

         end;

end;

procedure show(i,j:integer);  {输出从i到j的最短路径}  

begin

     while i<>j do begin

           write('-->',next[i,j]);i:=next[i,j];

     end;

end;

procedure print;  {输出最佳任务安排方案}

var i:integer;

begin

     write(1);

     for i:=1 to bests-1 do

         show(bestd[i],bestd[i+1]);

     writeln;

     writeln('Min cost=',mincost);

end;

begin

     init;

     try;

     print;

end.

  1. 多处理机调度问题:

任务一:jobs_1.pas

program jobs_1;

const maxn=100;  {处理机的最多数目}

      maxm=100;  {作业的最多数目}

var

   t:array[1..maxm] of timeint;   {t[i]--处理作业i需要的时间}

   time,        {time[i]--第i台处理机的处理时间}

   l, {l[i]--第i台处理机处理作业的数目}

   l1:array[0..maxn] of timeint; {l1[i]--目前最优解中第i台处理机处理作业的数目}

   a, {a[i,j]--第i台处理机处理的第j个作业耗费的时间}

   a1:array[1..maxn,1..maxm] of integer;

   {a1[i,j]--目前最优解中第i台处理机处理的第j个作业耗费的时间}

   done:array[1..maxm] of boolean; {done[i]--true表示作业i已完成,false表示未完成}

   least, {处理时间的下界}

   i,j,k,n,m,

   min, {目前最优解的处理时间}

   rest:integer; {剩余作业的总时间}

procedure print;  {输出最优解}

var i,j:integer;

begin

     for i:=1 to n do

         begin

              write(i,':');

              for j:=1 to l1[i] do

                  write(a1[i,j]:4);

              writeln;

         end;

     writeln('T0=',time[0]+1);

end;

procedure readp;  {读入数据}

var

   f:text;

   st:string;

   i,j,k:integer;

begin

     write('File name:');readln(st);

     assign(f,st);reset(f);

     readln(f,n,m);

     for i:=1 to m do

  begin

          read(f,t[i]);inc(rest,t[i]);

         end;

     close(f);

     least:=(rest-1) div n+1;  {定下界}

     for i:=1 to m-1 do  {排序}

         for j:=i+1 to m do

             if t[j]>t[i] then

                begin k:=t[i];t[i]:=t[j];t[j]:=k end;

end;

procedure try(p,q:integer);  {从p--m中选取作业放到处理机q上}

var j:integer;

    z:boolean;

begin

     

     z:=true;

     for j:=p to m do

         if not done[j] and (time[q]+t[j]<=time[q-1]) then  {选择合适的作业}

            begin

                 z:=false;done[j]:=true;

                 inc(l[q]);a[q,l[q]]:=t[j];inc(time[q],t[j]);dec(rest,t[j]);

                 try(j+1,q);

                 dec(l[q]);dec(time[q],t[j]);inc(rest,t[j]);done[j]:=false;

   if time[1]>time[0] then exit;

   {找到解后退回处理机1,需更新time[1],使之减小到time[0]}

   {2--n台处理机就不需再搜索}

            end;

     if z and ((n-q)*time[q]>=rest) then  {如果处理机q已无法放任何作业}

        if rest=0 then  {找到一组解}

           begin

                a1:=a;l1:=l;

                time[0]:=time[1]-1;

                if time[1]=least then

                   begin print;halt end;

           end

        else if q<n then  {继续搜索}

                try(1,q+1);

end;

begin

     readp;

     fillchar(time,sizeof(time),0);

     fillchar(a,sizeof(a),0);

     fillchar(l1,sizeof(l1),0);

     fillchar(l,sizeof(l),0);

     for i:=1 to m do  {贪心求上界}

         begin

              k:=1;

              for j:=2 to n do

                  if time[j]<time[k] then k:=j;

              time[k]:=time[k]+t[i];

              l1[k]:=l1[k]+1;

              a1[k,l1[k]]:=t[i];

         end;

     min:=time[1];time[0]:=min-1;

     for i:=2 to n do

         if time[i]>min then min:=time[i];

     if min=least then  {如上下界相等}

        begin

             print;

             halt;

        end;

     fillchar(time,sizeof(time),0);

     time[0]:=min-1;  {将上界减1,以找到更优的解}

     try(1,1);

     print;

end.

 任务二:jobs_2.pas

program jobs_2;

const maxn=100;  {处理机的最多数目}

      maxm=100;  {作业的最多数目}

var

   t:array[1..maxm] of timeint;   {t[i]--处理作业i需要的时间}

   time,        {time[i]--第i台处理机的处理时间}

   l, {l[i]--第i台处理机处理作业的数目}

   l1:array[0..maxn] of timeint; {l1[i]--目前最优解中第i台处理机处理作业的数目}

   a, {a[i,j]--第i台处理机处理的第j个作业耗费的时间}

   a1:array[1..maxn,1..maxm] of integer;

   {a1[i,j]--目前最优解中第i台处理机处理的第j个作业耗费的时间}

   done:array[1..maxm] of boolean; {done[i]--true表示作业i已完成,false表示未完成}

   least, {处理时间的下界}

   i,j,k,tmax,m,

   min, {目前最优解的处理时间}

   rest:integer; {剩余作业的总时间}

procedure print;  {输出最优解}

var i,j:integer;

begin

     for i:=1 to least do

         begin

              write(i,':');

              for j:=1 to l1[i] do

                  write(a1[i,j]:4);

              writeln;

         end;

     writeln('Min=',least);

end;

procedure readp;  {读入数据}

var

   f:text;

   st:string;

   i,j,k:integer;

begin

     write('File name:');readln(st);

     assign(f,st);reset(f);

     readln(f,tmax,m);

     for i:=1 to m do begin

         read(f,t[i]);inc(rest,t[i]);

     end;

     close(f);

     least:=(rest-1) div tmax+1;  {确定下界}

     for i:=1 to m-1 do  {排序}

         for j:=i+1 to m do

             if t[j]>t[i] then

                begin k:=t[i];t[i]:=t[j];t[j]:=k end;

end;

procedure try(p,q:integer); {从p--m中选取作业放到处理机q上}

var j:integer;

    z:boolean;

begin

     z:=true;

     for j:=p to m do

         if not done[j] and (time[q]+t[j]<=time[q-1]) then  {找到合适的作业}

            begin

                 z:=false;done[j]:=true;

                 inc(l[q]);a[q,l[q]]:=t[j];inc(time[q],t[j]);dec(rest,t[j]);

                 try(j+1,q);

                 dec(l[q]);dec(time[q],t[j]);inc(rest,t[j]);done[j]:=false;

            end;

     if z and ((least-q)*time[q]>=rest) then  {如果处理机q已无法放任何作业}

        if rest=0 then  {找到最优解}

           begin

                a1:=a;l1:=l;

              print;halt

           end

        else if q<min then  {继续搜索}

                try(1,q+1);

end;

begin

     readp;

     for i:=1 to m do  {判断无解情况,即某一任务所需时间超过规定时间}

         if t[i]>tmax then

            begin writeln('No answer!');exit end;

     repeat

           fillchar(time,sizeof(time),0);

           fillchar(l,sizeof(l),0);

           fillchar(l1,sizeof(l1),0);

           for i:=1 to m do  {贪心求上界}

               begin

                    k:=1;

                    for j:=2 to least do

                        if time[j]<time[k] then k:=j;

                    time[k]:=time[k]+t[i];

                    l1[k]:=l1[k]+1;

                    a1[k,l1[k]]:=t[i];

               end;

           min:=time[1];

           for i:=2 to least do

               if time[i]>min then min:=time[i];

           if min=least then  {如果贪心得出了最优解}

              begin

                   print;halt;

              end;

           fillchar(time,sizeof(time),0);

           time[0]:=tmax;

           try(1,1);

           inc(least);  {下界加一}

     until least>m;

     print;

end.

参考书目

  1. 《国际国内青少年信息学(计算机)奥林匹克竞赛试题解析(1994-1995》,吴文虎,王建德主编,清华大学出版社。
  2. 《奥林匹克计算机(信息学)入门》,江文哉主编,上海交通大学出版社。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker与phpstudy两种方式部署wordpress 并 开启伪静态

实际测试&#xff0c;可能是docker内存限制的缘故&#xff0c;docker部署的会比较卡 下载 wordpress phpstudy phpstudy中伪静态配置 伪静态 正常访问 WordPress 文章页的 URL 地址为 http://asa/index.php?p123。变成伪静态就是http://asa/123.html 。 伪静态是相对真实静…

【seaweedfs】3、f4: Facebook’s Warm BLOB Storage System 分布式对象存储的冷热数据

论文地址 Facebook的照片、视频和其他需要可靠存储和快速访问的二进制大型对象(BLOB)的语料库非常庞大&#xff0c;而且还在继续增长。随着BLOB占用空间的增加&#xff0c;将它们存储在我们传统的存储系统-- Haystack 中变得越来越低效。为了提高我们的存储效率(以Blob的有效复…

XML—标记语言

什么是XML&#xff1f; Extensible Markup Language&#xff0c;可扩展标记语言。 那标记语言是什么&#xff1f; 用文字做标记表达一些效果或携带一些数据。比如&#xff1a;HTML、XML 我的理解&#xff1a;用倾盆大雨表达雨很大 那XML为什么说是可扩展的呢&#xff1f; 还…

国产系统下开发QT程序总结

国产系统下开发QT程序总结 1. 国产系统简介 开发国产系统客户端的过程中&#xff0c;会出现兼容性问题。以下介绍Kylin和UOS环境下开发QT程序&#xff0c; 首先麒麟和统信这两个系统基于Ubuntu开发的。所以在Ubuntu开发理论上在国产系统上也能运行。芯片架构又分为amd,arm,mi…

持续性能优化:确保应用保持高性能

在当今数字化时代&#xff0c;应用程序的性能已经成为用户体验和业务成功的关键因素之一。无论是Web应用、移动应用还是企业级软件&#xff0c;用户对于速度和响应性的要求越来越高。因此&#xff0c;持续性能优化已经成为保证应用在竞争激烈的市场中脱颖而出的重要策略。 什么…

【CSS】解决对齐的小问题

问题&#xff1a; 表单或者页面上可能遇到文字无法对平均分&#xff0c;带有冒号的文本无法左右对齐的情况 常见的解决方式&#xff1a; 解决如下图 仍无法解决对齐的问题&#xff0c;还需要考虑字数 解决 这里用css的方式解决 增加 i 标签 固定宽度&#xff0c;设置 i …

Python股票交易---均值回归

免责声明&#xff1a;本文提供的信息仅用于教育目的&#xff0c;不应被视为专业投资建议。在做出投资决策时进行自己的研究并谨慎行事非常重要。投资涉及风险&#xff0c;您做出的任何投资决定完全由您自己负责。 在本文中&#xff0c;您将了解什么是均值回归交易算法&#xff…

Leetcode每日一题:1448. 统计二叉树中好节点的数目

原题 给你一棵根为 root 的二叉树&#xff0c;请你返回二叉树中好节点的数目。 「好节点」X 定义为&#xff1a;从根到该节点 X 所经过的节点中&#xff0c;没有任何节点的值大于 X 的值。 示例 1&#xff1a; 输入&#xff1a;root [3,1,4,3,null,1,5] 输出&#xff1a;4 解…

微服务(rpc)

微服务&#xff08;rpc&#xff09; 微服务必备的模块生产者消费者管理平台流量控制集群情况下如何做到流量监控 负载均衡服务发现和治理序列化传输序列化和反序列化 微服务是一种架构风格&#xff0c;将一个应用程序拆分为一组小型、独立的服务&#xff0c;每个服务都可以独立…

Elasticsearch 集成---框架集成SpringData-集成测试-索引操作

1.Spring Data 框架介绍 Spring Data 是一个用于简化数据库、非关系型数据库、索引库访问&#xff0c;并支持云服务的 开源框架。其主要目标是使得对数据的访问变得方便快捷&#xff0c;并支持 map-reduce 框架和云计 算数据服务。 Spring Data 可以极大的简化 JPA &a…

GraphQL渗透测试案例及防御办法

什么是GraphQL GraphQL 是一种 API 查询语言&#xff0c;旨在促进客户端和服务器之间的高效通信。它使用户能够准确指定他们在响应中所需的数据&#xff0c;从而有助于避免有时使用 REST API 看到的大型响应对象和多个调用。 GraphQL 服务定义了一个合约&#xff0c;客户端可…

Java【手撕滑动窗口】LeetCode 3. “无重复字符的最长子串“, 图文详解思路分析 + 代码

文章目录 前言一、长度最小子数组1, 题目2, 思路分析3, 代码 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: &#x1f4d5; JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统等 &#x1f4d7; Java数据结构: 顺序表, 链…

pytest pytest.ini 配置日志输出至文件

创建pytest.ini 文件 [pytest] log_file pytest_log.txt log_file_level INFO log_file_date_format %Y-%m-%d %H:%M:%S log_file_format %(asctime)s | %(filename)s | %(funcName)s | line:%(lineno)d | %(levelname)s | %(message)s import pytest import loggingdef …

华为OD机试 - 租车骑绿道 - 双指针(Java 2023 B卷 100分)

目录 一、题目描述二、输入描述三、输出描述四、解题思路1、输入2、输出3、说明4、双指针算法 五、Java算法源码六、效果展示 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 一、题目描述 部门组织绿岛骑行团建活动&#xff0c;租用公共双人自行车骑行&#xff0c;…

谈谈对OceanBase单机分布式一体化的思考

关于作者&#xff1a; 杨传辉&#xff0c;OceanBase CTO。2010 年作为创始成员之一加入 OceanBase 团队&#xff0c;主导了 OceanBase 历次架构设计和技术研发&#xff0c;从无到有实现 OceanBase 在蚂蚁集团全面落地。同时&#xff0c;他也主导了两次 OceanBase TPC-C 测试并打…

Spring Boot(Vue3+ElementPlus+Axios+MyBatisPlus+Spring Boot 前后端分离)【四】

&#x1f600;前言 本篇博文是关于Spring Boot(Vue3ElementPlusAxiosMyBatisPlusSpring Boot 前后端分离)【四】&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章…

JavaScript设计模式(一)——构造器模式、原型模式、类模式

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

JVM 是怎么设计来保证new对象的线程安全

1、采用 CAS 分配重试的方式来保证更新操作的原子性 2、每个线程在 Java 堆中预先分配一小块内存&#xff0c;也就是本地线程分配缓冲&#xff08;Thread Local AllocationBuffer&#xff0c;TLAB&#xff09;&#xff0c;要分配内存的线程&#xff0c;先在本地缓冲区中分配&a…

【高危】Apache Airflow Spark Provider 反序列化漏洞 (CVE-2023-40195)

zhi.oscs1024.com​​​​​ 漏洞类型反序列化发现时间2023-08-29漏洞等级高危MPS编号MPS-qkdx-17bcCVE编号CVE-2023-40195漏洞影响广度广 漏洞危害 OSCS 描述Apache Airflow Spark Provider是Apache Airflow项目的一个插件&#xff0c;用于在Airflow中管理和调度Apache Spar…

16、Flink 的table api与sql之连接外部系统: 读写外部系统的连接器和格式以及Elasticsearch示例(2)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…