信息奥赛经典算法总结.docx
- 文档编号:23527359
- 上传时间:2023-05-17
- 格式:DOCX
- 页数:66
- 大小:68.87KB
信息奥赛经典算法总结.docx
《信息奥赛经典算法总结.docx》由会员分享,可在线阅读,更多相关《信息奥赛经典算法总结.docx(66页珍藏版)》请在冰豆网上搜索。
信息奥赛经典算法总结
信息学奥林匹克竞赛
经典算法总结
三.全排列与组合的生成
四.递推
五.递归
六.回朔
七.最短路径算法及应用
八.动态规划
九.求最小生成树
十.树的遍历顺序转换
十一.查找算法
十二.算符优先法求解表达式求值问题
一.高精度
1.高精度加法
2.高精度减法
3.高精度乘法
4.高精度除法
二.排序
1.冒泡排序
2.插入排序
3.分治排序
4.直接选择排序
5.快速排序
6.希尔排序
7.归并排序
8.拓扑排序
9.堆排序
高精度
一、高精度加法(回首页)
所谓的高精度运算,是指参与运算的数(加数,减数,因子……)范围大大超出了标准数据类型(整型,实型)能表示的范围的运算。
例如,求两个200位的数的和。
这时,就要用到高精度算法了。
在这里,我们先讨论高精度加法。
高精度运算主要解决以下三个问题:
基本方法
1、加数、减数、运算结果的输入和存储
运算因子超出了整型、实型能表示的范围,肯定不能直接用一个数的形式来表示。
在Pascal中,能表示多个数的数据类型有两种:
数组和字符串。
(1)数组:
每个数组元素存储1位(在优化时,这里是一个重点!
),有多少位就需要多少个数组元素;
用数组表示数的优点:
每一位都是数的形式,可以直接加减;运算时非常方便
用数组表示数的缺点:
数组不能直接输入;输入时每两位数之间必须有分隔符,不符合数值的输入习惯;
(2)字符串:
字符串的最大长度是255,可以表示255位。
用字符串表示数的优点:
能直接输入输出,输入时,每两位数之间不必分隔符,符合数值的输入习惯;
用字符串表示数的缺点:
字符串中的每一位是一个字符,不能直接进行运算,必须先将它转化为数值再进行运算;运算时非常不方便;
(3)综合以上所述,对上面两种数据结构取长补短:
用字符串读入数据,用数组存储数据:
vars1,s2:
string;
a,b,c:
array[1..260]ofinteger;
i,l,k1,k2:
integer;
begin
write('inputs1:
');readln(s1);
write('inputs2:
');readln(s2);
{----读入两个数s1,s2,都是字符串类型}
l:
=length(s1);{求出s1的长度,也即s1的位数;有关字符串的知识。
}
k1:
=260;
fori:
=ldownto1do
begin
a[k1]:
=ord(s1[i])-48;{将字符转成数值}
k1:
=k1-1;
end;
k1:
=k1+1;
{----以上将s1中的字符一位一位地转成数值并存在数组a中;低位在后(从第260位开始),高位在前(每存完一位,k1减1)}
对s2的转化过程和上面一模一样。
2、运算过程
在往下看之前,大家先列竖式计算35+86。
注意的问题:
(1)运算顺序:
两个数靠右对齐;从低位向高位运算;先计算低位再计算高位;
(2)运算规则:
同一位的两个数相加再加上从低位来的进位,成为该位的和;这个和去掉向高位的进位就成为该位的值;如上例:
3+8+1=12,向前一位进1,本位的值是2;可借助MOD、DIV运算完成这一步;
(3)最后一位的进位:
如果完成两个数的相加后,进位位值不为0,则应添加一位;
(4)如果两个加数位数不一样多,则按位数多的一个进行计算;
ifk1>k2thenk:
=k1elsek:
=k2;
y:
=0;
fori:
=260downtokdo
begin
x:
=a[i]+b[i]+y;
c[i]:
=xmod10;
y:
=xdiv10;
end;
ify<>0thenbegink:
=k-1;c[k]:
=y;end;
3、结果的输出(这也是优化的一个重点)
按运算结果的实际位数输出
fori:
=kto260dowrite(c[i]);
writeln;
4、例子:
求两个数的加法
programsum;
vars,s1,s2:
string;
a,b,c:
array[1..260]ofinteger;
i,l,k1,k2:
integer;
begin
write('inputs1:
');readln(s1);
write('inputs2:
');readln(s2);
l:
=length(s1);
k1:
=260;
fori:
=ldownto1do
begin
a[k1]:
=ord(s1[i])-48;
k1:
=k1-1;
end;
k1:
=k1+1;
l:
=length(s2);
k2:
=260;
fori:
=ldownto1do
begin
b[k2]:
=ord(s2[i])-48;
k2:
=k2-1;
end;
k2:
=k2+1;
ifk1>k2thenk:
=k2elsek:
=k1;
y:
=0;
fori:
=260downtokdo
begin
x:
=a[i]+b[i]+y;
c[i]:
=xmod10;
y:
=xdiv10;
end;
ify<>0thenbegink:
=k-1;c[k]:
=y;
end;
fori:
=kto260dowrite(c[i]);
writeln;
end.
优化:
以上的方法的有明显的缺点:
(1)浪费空间:
一个整型变量(-32768~32767)只存放一位(0~9);
(2)浪费时间:
一次加减只处理一位;
针对以上问题,我们做如下优化:
一个数组元素存放四位数;(integer的最大范围是32767,5位的话可能导致出界)。
具体方法:
l:
=length(s1);
k1:
=260;
repeat {----有关字符串的知识}
s:
=copy(s1,l-3,4);
val(s,a[k1],code);
k1:
=k1-1;
s1:
=copy(s1,1,l-4);
l:
=l-4;
untill<=0;
k1:
=k1+1;
而因为这个改进,算法要相应改变:
(1)运算时:
不再逢十进位,而是逢万进位(mod10000;div10000);
(2)输出时:
最高位直接输出,其余各位,要判断是否足够4位,不足部分要补0;例如:
1,23,2345这样三段的数,输出时,应该是100232345而不是1234567。
改进后的算法:
programsum;
vars,s1,s2:
string;
a,b,c:
array[1..260]ofinteger;
x,y,k,i,l,k1,k2,code:
integer;
begin
write('inputs1:
');readln(s1);
write('inputs2:
');readln(s2);
l:
=length(s1);
k1:
=260;
repeat{----有关字符串的知识}
s:
=copy(s1,l-3,4);
val(s,a[k1],code);
k1:
=k1-1;
s1:
=copy(s1,1,l-4);
l:
=l-4;
untill<=0;
k1:
=k1+1;
l:
=length(s2);
k2:
=260;
repeat
s:
=copy(s2,l-3,4);
val(s,b[k2],code);
k2:
=k2-1;
s2:
=copy(s2,1,l-4);
l:
=l-4;
untill<=0;
k2:
=k2+1;
ifk1 =k1elsek: =k2; y: =0; fori: =260downtokdo begin x: =a[i]+b[i]+y; c[i]: =xmod10000; y: =xdiv10000; end; ify<>0thenbegink: =k-1;c[k]: =y;end; write(c[k]); fori: =k+1to260do begin ifc[i]<1000thenwrite('0'); ifc[i]<100thenwrite('0'); ifc[i]<10thenwrite('0'); write(c[i]); end; writeln; end. 2.高精度减法(回首页) 1、和高精度加法相比,减法在差为负数时处理的细节更多一点: 当被减数小于减数时,差为负数,差的绝对值是减数减去被减数;在程序实现上用一个变量来存储符号位,用另一个数组存差的绝对值。 2、算法流程: (1)读入被减数S1,S2(字符串); (2)置符号位: 判断被减数是否大于减数: 大则将符号位置为空;小则将符号位置为“-”,交换减数与被减数; (3)被减数与减数处理成数值,放在数组中; (4)运算: A、取数; B、判断是否需要借位; C、减,将运算结果放到差数组相应位中; D、判断是否运算完成: 是,转5;不是,转A; (5)打印结果: 符号位,第1位,循环处理第2到最后一位; 3、细节: ▲如何判断被减数与减数的大小: 字符串知识 (1)首先将两个字符串的位数补成一样(因为字符串的比较是从左边对齐的;两个字符串一样长才能真正地比较出大小): 短的在左边补0 k1: =length(s1); k2: =length(s2); ifk1>k2thenfori: =1tok1-k2dos2: ='0'+s2 elsefori: =1tok2-k1dos1: ='0'+s1; (2)接着比较大小: 直接比较字符串大小 fh: =''; ifs1 ='-';s: =s1;s1: =s2;s2: =s;end; {————s1存被减数,符号存符号} ▲将字符串处理成数值: l: =length(s1);{求出s1的长度,也即s1的位数;有关字符串的知识。 } k1: =260; fori: =ldownto1do begin a[k1]: =ord(s1[i])-48;{将字符转成数值} k1: =k1-1; end; k1: =k1+1; ▲打印结果: 例: 差: 第一位是12,第二位是234,第三位是1234,最后一位: 3。 它的实际数值是12023412340003。 从上例可以看出: 打印时,从第二位开始,因为每一段都代表4位,不足4位的要补足0。 write(fh,c[k]);{k是差的第1位;} fori: =k+1to260do begin ifc[i]<1000thenwrite('0'); ifc[i]<100thenwrite('0'); ifc[i]<10thenwrite('0'); write(c[i]); end; 4、参考程序: vara,b,c: array[1..100]ofinteger; x,y: string; i,j,max,m,n,l,code: integer; begin writeln; readln(x);readln(y); m: =length(x);n: =length(y); ifm =n elsemax: =m; fori: =1tomdoval(copy(x,m-i+1,1),a[i],code); forj: =1tondoval(copy(y,n-j+1,1),b[j],code); l: =0; fori: =1tomaxdo begin if(a[i]-l) begin c[i]: =a[i]+10-b[i]-l;l: =1; end else begin c[i]: =a[i]-b[i]-l; l: =0; end; end; i: =max; whilec[i]=0do i: =i-1; forj: =idownto1dowrite(c[i]); end. 3.高精度乘法(回首页) 一、高精度乘法基本思想和加法一样。 其基本流程如下: ①读入被乘数s1,乘数s2 ②把s1、s2分成4位一段,转成数值存在数组a,b中;记下a,b的长度k1,k2; ③i赋为b中的最低位; ④从b中取出第i位与a相乘,累加到另一数组c中;(注意: 累加时错开的位数应是多少位? ) ⑤i: =i-1;检测i值: 小于k2则转⑥,否则转④ ⑥打印结果 programgaojing_times; vara,b,c: array[1..100]ofinteger; x,y: string; i,j,max,m,n,l,code: integer; begin writeln; readln(x);readln(y); m: =length(x);n: =length(y); fori: =1tomdoval(copy(x,m-i+1,1),a[i],code); forj: =1tondoval(copy(y,n-j+1,1),b[j],code); l: =0; fori: =1tomdo forj: =1ton+1do begin c[i+j-1]: =c[i+j-1]+a[i]*b[j]+l; l: =c[i+j-1]div10; c[i+j-1]: =c[i+j-1]mod10; end; i: =m+n; whilec[i]=0do i: =i-1; forj: =idownto1dowrite(c[j]); end. 4.高精度除法(回首页) programgaojing_division; varx,y: longint; i,j,l,z: integer; begin writeln; readln(x);readln(y);readln(l); if(xmody)=0thenwrite(xdivy) else begin whilex>ydo begin write(xdivy); x: =xmody; end; write('0.'); fori: =1toldo begin x: =(xmody)*10; write(xdivy); end; end; end. 二.排序(回首页) 内部排序: 内存中 外部排序: 在外部存储器中 按不同策略: 插入、选择、交换、分配、归并 1.冒泡排序(回首页) FORI: =1TON-1DO FORJ: =I+1TONDO BEGIN IFA[I]>A[J]THEN BEGIN P: =A[I];A[I]: =A[J];A[J]: =P; END; END 2.插入排序(回首页) 思想: 在分发牌时,拿到一张牌后按其大小顺序插入到原有的牌中的适当位置,使手中的牌仍按大小顺序排序,这就是插入排序。 效率分析: 最多的比较次数是: 1+2+3+……+(n-1)=n(n-1)/2 最多的移动次数是: 1+2+3+……+(n-1)=n(n-1)/2 FORI: =2TONDO BEGIN A[0]: =A[I]; J: =I-1; WHILE(A[0]0)DO BEGIN A[J+1]: =A[J]; J: =J-1; END; A[J+1]: =A[0]; END; 3.二分法插入排序(回首页) 思想: 假设a[1],a[2],……a[I-1]已排序,取a[i/2]与a[I]比较, 如果a[i/2]>a[I]那应在a[1]到a[Idiv2-1]之前,再用二分法 如果a[Idiv2]<=a[I]那应在a[i/2+1]到a[I-1]之间,再用二分法 一般来说,在a[L]到a[h]之间用二分法,中结点a[(l+h)/2] 效率分析: 在比较次数上有所减少,而数据移动次数一样。 FORI: =2TONdo BEGIN X=A[I]; L=1; H: =I-1; WHILEL<=HDO BEGIN M: =(L+H)DIV2; IFX =M-1ELSEL: =M+1 END; FORJ: =I-1DOWNTOLDOA[J+1]: =A[J]; A[L]: =X; END 4.直接选择排序(回首页) 思路: 首先在所有数据中选最小的数据,把它与第一个数据交换,然后在其余的数据中再选出最小的数据与第二个数据交换,依次类推,直到全部排完。 程序核心如下: fori: =1tondoa[i]: =random(100); fori: =1ton-1do begin k: =i; forj: =i+1tondo
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 信息 经典 算法 总结
![提示](https://static.bdocx.com/images/bang_tan.gif)