• 分治算法(二)


    5取余运算(mod)

    源程序名              mod.???(pas, c, cpp)

    可执行文件名      mod.exe

    输入文件名          mod.in

    输出文件名          mod.out

    【问题描述】

    输入bpk的值,求b^p mod k的值。其中bpk*k为长整型数。

    【样例】

    mod.in

    2 10 9

    mod.out

    2^10 mod 9=7

    【知识准备】

    进制转换的思想、二分法。

    【算法分析】

         本题主要的难点在于数据规模很大(b, p都是长整型数),对于bp显然不能死算,那样的话时间复杂度和编程复杂度都很大。

         下面先介绍一个原理:a*b mod k(a mod k)*(b mod k)mod k。显然有了这个原理,就可以把较大的幂分解成较小的,因而免去高精度计算等复杂过程。

       那么怎样分解最有效呢?显然对于任何一个自然数P,有p=2*(p div 2)+p mod 2,如192*(19 div 2)+19 mod 22*9+1,利用上述原理就可以把b的19次方除以k的余数转换为求b9次方除以k的余数,即b19=b2*9+1=b*b9*b9,再进一步分解下去就不难求得整个问题的解。

         这是一个典型的分治问题,具体实现的时候是用递推的方法来处理的,

    p=19,有

    19=2*9+1                            b19=b1*b9*b9

    9=2*4+1                             b9=b1*b4*b4

    4=2*2+0                             b4=b0*b2*b2

    2=2*1+0                             b2=b0*b1*b1

    1=2*0+1                            b1=b1*b0*b0

    反过来,我们可以从0出发,通过乘以2再加上一个01而推出124919,这样就逐步得到了原来的指数,

    进而递推出以b为底,依次以这些数为指数的自然数除以k的余数。

    不难看出这里(倒推)每一次乘以2后要加的数就是19对应的二进制数的各位数字,即10011,而19(10011)2,求解的过程也就是将二进制数还原为十进制数的过程。

        具体实现请看下面的程序,程序中用数组binary存放p对应的二进制数,总位数为lenbinary[1]存放最底位。变量rest记录每一步求得的余数。

     1 var b,p,k,i,len,rest,temp:longint;
     2      binary:array[1..32] of longint;
     3 begin
     4   assign(input,'mod.in');
     5   assign(output,'mod.out');
     6   reset(input);
     7   rewrite(output);
     8   readln(b,p,k);   {输入三个数}
     9   len:=0;
    10   temp:=p;
    11   while temp<>0 do    {存放p的二进制转换}
    12     begin
    13       len:=len+1;
    14       binary[len]:=temp mod 2;  //也可以写成binary[len]:=temp and 1;
    15       temp:=temp div 2        //也可以写成temp:=temp shr 1;
    16     end;
    17   rest:=1;
    18   for i:=len downto 1 do    {用二分法实现b^p mod k}
    19     begin
    20       temp:=rest*rest mod k;
    21       if binary[i]=1 then rest:=b mod k * temp mod k    {如果是奇数,就多乘b}        //rest:=(b mod k * temp) mod k 
    22                      else rest:=temp     {否则就是rest*rest}
    23     end;
    24   writeln(b,'^',p,' mod ',k,' = ',rest);   {输出b^p mod k}
    25   close(input);
    26   close(output)
    27 end.

    6 黑白棋子的移动(chessman)

    源程序名                chessman.???(pas, c, cpp)

    可执行文件名        chessman.exe

    输入文件名            chessman.in

    输出文件名            chessman.out

     1 const max=100;
     2 var n,st,sp:integer;
     3     c:array[1..max] of char;  {工作场所}
     4 
     5 procedure print;  {打印}
     6   var i:integer;
     7   begin
     8     write('step',st:2,':');
     9     for i:=1 to 2*n+2 do write(c[i]);
    10     writeln;
    11     st:=st+1
    12   end;
    13 
    14 procedure init(n:integer);  {初始化}
    15   var i:integer;
    16   begin
    17     st:=0;
    18     sp:=2*n+1;
    19     for i:=1 to n do c[i]:='o';
    20     for i:=n+1 to 2*n do c[i]:='*';
    21     c[2*n+1]:='-';c[2*n+2]:='-';  
    22     print
    23   end;
    24 
    25 procedure move(k:integer);  {移动一步}//将两个横线(空)移到k处(以左横线位置为序号)
    26   var j:integer;
    27   begin
    28     for j:=0 to 1 do begin c[sp+j]:=c[k+j];c[k+j]:='-';end;
    29     sp:=k;
    30     print
    31   end;
    32 
    33 procedure mv(n:integer);    {主要过程}
    34   var i,k:integer;
    35   begin
    36     if n=4 then begin
    37                   move(4);
    38                   move(8);
    39                   move(2);
    40                   move(7);
    41                   move(1)
    42                 end
    43            else begin
    44                   move(n);
    45                   move(2*n-1);
    46                   mv(n-1)
    47                 end
    48   end;
    49 
    50 begin  {main}
    51   assign(input,'chessman.in');
    52   assign(output,'chessman.out');
    53   reset(input);
    54   rewrite(output);
    55   readln(n);
    56   init(n);
    57   mv(n);
    58   close(input);
    59   close(output)
    60 end.

    7、小车问题(car

    【问题描述】 

    甲、乙两人同时从A地出发要尽快同时赶到 B地。出发时地有一辆小车,可是这辆小车除了驾驶员外只能带一人。已知甲、乙两人的步行速度一样,且小于车的速度。问:怎样利用小车才能使两人尽快同时到达。 

    【问题输入】 

    仅一行,三个数据分别表示 AB两地的距离s,人的步行速度a,车的速度 b。 

    【问题输出】 

    两人同时到达B地需要的最短时间。

    【输入输出样例】 

    car.in 

    120  5  25 

    car.out 

    9.6000000000E+00

    自己推了一下确实是这样的。数学太弱了。。。

     1 var
     2   s,a,b,k,x,t:real;
     3 begin
     4 assign(input,'car.in');
     5 reset(input);
     6 assign(output,'car.out');
     7 rewrite(output);
     8   readln(s,a,b);
     9    k:=s*(a+b)/(3*a+b);
    10    t:=k/b+(s-k)/a;
    11   writeln(t:0:2);
    12 close(input);close(output);
    13 end.
    数学法

     1 program car1(input,output); 
     2 const zero=1e-4; 
     3 var s,a,b,c,c0,c1,t1,t2,t3,t4:real; 
     4 BEGIN 
     5 assign(input,’car.in’); 
     6 assign(output,’car.out’); 
     7 reset(input); 
     8 rewrite(output); 
     9   readln(s,a,b); 
    10   c0:=0; 
    11   c1:=s; 
    12   repeat 
    13     c:=(c0+c1)/2; 
    14     t3:=c/b;  //甲到K乘汽车用时;也是乙走到C用时。即 乙TAC=甲TAK
    15     t1:=t3+(s-c)/a;  //甲到终点用时。即 甲TAB
    16     t4:=(c-t3*a)/(a+b);  //乙从C走,车从K来接乙相遇用时。即 乙TCD
    17     t2:=t3+t4+(s-(t3+t4)*a)/b;   //乙到终点用时。即 乙TAB
    18     if t1<t2 then c1:=c else c0:=c;   //甲的时间短,走得快,则让汽车少载一段甲;乙的时间短,走得快,则让汽车多载一段甲
    19   until abs(t1-t2)<zero; 
    20   writeln(t1); 
    21   close(input); 
    22 close(output) 
    23 end.
    分治法

    【深入思考】 

    现在把上述问题稍改一下,已知 AB两地相距 S=100公里,在地有 n人,现有一辆汽车,此汽车除司机外只能载 人,已知汽车的速度为 V1=50 公里/小时,人的速度为 V2=5公里/小时。要求设计一种方案,使得最后一个人用最少的时间到达B

    8 麦森数(mason)

    源程序名              mason.???(pas, c, cpp)

    可执行文件名      mason.exe

    输入文件名          mason.in

    输出文件名          mason.out

    【问题描述】

        形如2p-1的素数称为麦森数,这时P一定也是个素数。但反过来不一定,即如果P是个素数,2p-1不一定也是素数。到1998年底,人们已找到了37个麦森数。最大的一个是P=3021377,它有909526位。麦森数有许多重要应用,它与完全数密切相关。

        任务:从文件中输入P(1000<P<3100000),计算2p-1的位数和最后500位数字(用十进制高精度数表示)。

    【输入】

    文件中只包含一个整数P(1000<P<3100000)。

    【输出】

    第一行:十进制高精度数2p-1的位数;

    2~11行:十进制高精度数2p-1的最后500位数字(每行输出50位,共输出10行,不足500位时高位补0);

        不必验证2p-1P是否为素数。

    【样例】

    mason.in

    1279

    mason.out

    386

    00000000000000000000000000000000000000000000000000

    00000000000000000000000000000000000000000000000000

    00000000000000104079321946643990819252403273640855

    38615262247266704805319112350403608059673360298012

    23944173232418484242161395428100779138356624832346

    49081399066056773207629241295093892203457731833496

    61583550472959420547689811211693677147548478866962

    50138443826029173234888531116082853841658502825560

    46662248318909188018470682222031405210266984354887

    32958028878050869736186900714720710555703168729087

  • 相关阅读:
    python上传阿里云oss
    python调用百度图片识别api
    python实现sm2和sm4国密(国家商用密码)算法
    python坐标获取经纬度或经纬度获取坐标免费模块--geopy
    剑指 Offer 36. 二叉搜索树与双向链表
    vs code中终端中的命令不能使用的解决方法
    VS Code切换默认终端(cmd、powershell)
    剑指 Offer 35. 复杂链表的复制
    剑指 Offer 33. 二叉搜索树的后序遍历序列
    剑指 Offer 32
  • 原文地址:https://www.cnblogs.com/vacation/p/5183020.html
Copyright © 2020-2023  润新知