常用的100个经典算法.docx
- 文档编号:30059447
- 上传时间:2023-08-04
- 格式:DOCX
- 页数:35
- 大小:25.95KB
常用的100个经典算法.docx
《常用的100个经典算法.docx》由会员分享,可在线阅读,更多相关《常用的100个经典算法.docx(35页珍藏版)》请在冰豆网上搜索。
常用的100个经典算法
100个基本算法
1.数论算法
求两数的最大公约数
functiongcd(a,b:
integer):
integer;
begin
ifb=0thengcd:
=a
elsegcd:
=gcd(b,amodb);
end;
求两数的最小公倍数
functionlcm(a,b:
integer):
integer;
begin
ifa lcm: =a; whilelcmmodb>0doinc(lcm,a); end; 素数的求法 A.小范围内判断一个数是否为质数: functionprime(n: integer): Boolean; varI: integer; begin forI: =2totrunc(sqrt(n))do ifnmodI=0thenbegin prime: =false;exit; end; prime: =true; end; B.判断longint范围内的数是否为素数(包含求50000以内的素数表): proceduregetprime; var i,j: longint; p: array[1..50000]ofboolean; begin fillchar(p,sizeof(p),true); p[1]: =false; i: =2; whilei<50000dobegin ifp[i]thenbegin j: =i*2; whilej<50000dobegin p[j]: =false; inc(j,i); end; end; inc(i); end; l: =0; fori: =1to50000do ifp[i]thenbegin inc(l);pr[l]: =i; end; end;{getprime} functionprime(x: longint): integer; vari: integer; begin prime: =false; fori: =1toldo ifpr[i]>=xthenbreak elseifxmodpr[i]=0thenexit; prime: =true; end;{prime} 2. 3. 4.求最小生成树 A.Prim算法: procedureprim(v0: integer); var lowcost,closest: array[1..maxn]ofinteger; i,j,k,min: integer; begin fori: =1tondobegin lowcost[i]: =cost[v0,i]; closest[i]: =v0; end; fori: =1ton-1dobegin {寻找离生成树最近的未加入顶点k} min: =maxlongint; forj: =1tondo if(lowcost[j] min: =lowcost[j]; k: =j; end; lowcost[k]: =0;{将顶点k加入生成树} {生成树中增加一条新的边k到closest[k]} {修正各点的lowcost和closest值} forj: =1tondo ifcost[k,j] lowcost[j]: =cost[k,j]; closest[j]: =k; end; end; end;{prim} B.Kruskal算法: (贪心) 按权值递增顺序删去图中的边,若不形成回路则将此边加入最小生成树。 functionfind(v: integer): integer;{返回顶点v所在的集合} vari: integer; begin i: =1; while(i<=n)and(notvinvset[i])doinc(i); ifi<=nthenfind: =ielsefind: =0; end; procedurekruskal; var tot,i,j: integer; begin fori: =1tondovset[i]: =[i];{初始化定义n个集合,第I个集合包含一个元素I} p: =n-1;q: =1;tot: =0;{p为尚待加入的边数,q为边集指针} sort; {对所有边按权值递增排序,存于e[I]中,e[I].v1与e[I].v2为边I所连接的两个顶点的序号,e[I].len为第I条边的长度} whilep>0dobegin i: =find(e[q].v1);j: =find(e[q].v2); ifi<>jthenbegin inc(tot,e[q].len); vset[i]: =vset[i]+vset[j];vset[j]: =[]; dec(p); end; inc(q); end; writeln(tot); end; 5.最短路径 A.标号法求解单源点最短路径: var a: array[1..maxn,1..maxn]ofinteger; b: array[1..maxn]ofinteger;{b[i]指顶点i到源点的最短路径} mark: array[1..maxn]ofboolean; procedurebhf; var best,best_j: integer; begin fillchar(mark,sizeof(mark),false); mark[1]: =true;b[1]: =0;{1为源点} repeat best: =0; fori: =1tondo Ifmark[i]then{对每一个已计算出最短路径的点} forj: =1tondo if(notmark[j])and(a[i,j]>0)then if(best=0)or(b[i]+a[i,j] best: =b[i]+a[i,j];best_j: =j; end; ifbest>0thenbegin b[best_j]: =best;mark[best_j]: =true; end; untilbest=0; end;{bhf} B.Floyed算法求解所有顶点对之间的最短路径: procedurefloyed; begin forI: =1tondo forj: =1tondo ifa[I,j]>0thenp[I,j]: =Ielsep[I,j]: =0;{p[I,j]表示I到j的最短路径上j的前驱结点} fork: =1tondo{枚举中间结点} fori: =1tondo forj: =1tondo ifa[i,k]+a[j,k] a[i,j]: =a[i,k]+a[k,j]; p[I,j]: =p[k,j]; end; end; C.Dijkstra算法: 类似标号法,本质为贪心算法。 var a: array[1..maxn,1..maxn]ofinteger; b,pre: array[1..maxn]ofinteger;{pre[i]指最短路径上I的前驱结点} mark: array[1..maxn]ofboolean; proceduredijkstra(v0: integer); begin fillchar(mark,sizeof(mark),false); fori: =1tondobegin d[i]: =a[v0,i]; ifd[i]<>0thenpre[i]: =v0elsepre[i]: =0; end; mark[v0]: =true; repeat{每循环一次加入一个离1集合最近的结点并调整其他结点的参数} min: =maxint;u: =0;{u记录离1集合最近的结点} fori: =1tondo if(notmark[i])and(d[i] u: =i;min: =d[i]; end; ifu<>0thenbegin mark[u]: =true; fori: =1tondo if(notmark[i])and(a[u,i]+d[u] d[i]: =a[u,i]+d[u]; pre[i]: =u; end; end; untilu=0; end; D.计算图的传递闭包 ProcedureLonglink; Var T: array[1..maxn,1..maxn]ofboolean; Begin Fillchar(t,sizeof(t),false); Fork: =1tondo ForI: =1tondo Forj: =1tondoT[I,j]: =t[I,j]or(t[I,k]andt[k,j]); End; 6.0-1背包问题(部分背包问题可有贪心法求解: 计算Pi/Wi) 数据结构: w[i]: 第i个背包的重量; p[i]: 第i个背包的价值; (1)0-1背包: 每个背包只能使用一次或有限次(可转化为一次): A.求最多可放入的重量。 NOIP2001装箱问题 有一个箱子容量为v(正整数,o≤v≤20000),同时有n个物品(o≤n≤30),每个物品有一个体积(正整数)。 要求从n个物品中,任取若千个装入箱内,使箱子的剩余空间为最小。 l搜索方法 proceduresearch(k,v: integer);{搜索第k个物品,剩余空间为v} vari,j: integer; begin ifv =v; ifv-(s[n]-s[k-1])>=bestthenexit;{s[n]为前n个物品的重量和} ifk<=nthenbegin ifv>w[k]thensearch(k+1,v-w[k]); search(k+1,v); end; end; lDP F[I,j]为前i个物品中选择若干个放入使其体积正好为j的标志,为布尔型。 实现: 将最优化问题转化为判定性问题 F[I,j]=f[i-1,j-w[i]](w[I]<=j<=v)边界: f[0,0]: =true. ForI: =1tondo Forj: =w[I]tovdoF[I,j]: =f[I-1,j-w[I]]; 优化: 当前状态只与前一阶段状态有关,可降至一维。 F[0]: =true; ForI: =1tondobegin F1: =f; Forj: =w[I]tovdo Iff[j-w[I]]thenf1[j]: =true; F: =f1; End; B.求可以放入的最大价值。 F[I,j]= C.求恰好装满的情况数。 (2)每个背包可使用任意次: A.求最多可放入的重量。 状态转移方程为 f[I,j]=max{f[i-w[j] B.求可以放入的最大价值。 USACO1.2ScoreInflation 进行一次竞赛,总时间T固定,有若干种可选择的题目,每种题目可选入的数量不限,每种题目有一个ti(解答此题所需的时间)和一个si(解答此题所得的分数),现要选择若干题目,使解这些题的总时间在T以内的前提下,所得的总分最大,求最大的得分。 *易想到: f[i,j]=max{f[i-k*w[j],j-1]+k*v[j]}(0<=k<=idivw[j]) 其中f[i,j]表示容量为i时取前j种背包所能达到的最大值。 *优化: Begin FillChar(problem,SizeOf(problem),0); Assign(Input,'inflate.in'); Reset(Input); Readln(M,N); Fori: =1ToNDo Withproblem[i]Do Readln(point,time); Close(Input); FillChar(f,SizeOf(f),0); Fori: =1ToMDo Forj: =1ToNDo Ifi-problem[j].time>=0Then Begin t: =problem[j].point+f[i-problem[j].time]; Ift>f[i]Thenf[i]: =t; End; Assign(Output,'inflate.out'); Rewrite(Output); Writeln(f[M]); Close(Output); End. C.求恰好装满的情况数。 AhOI2001Problem2 求自然数n本质不同的质数和的表达式的数目。 思路一,生成每个质数的系数的排列,在一一测试,这是通法。 proceduretry(dep: integer); vari,j: integer; begin cal;{此过程计算当前系数的计算结果,now为结果} ifnow>nthenexit;{剪枝} ifdep=l+1thenbegin{生成所有系数} cal; ifnow=ntheninc(tot); exit; end; fori: =0tondivpr[dep]dobegin xs[dep]: =i; try(dep+1); xs[dep]: =0; end; end; 思路二,递归搜索效率较高 proceduretry(dep,rest: integer); vari,j,x: integer; begin if(rest<=0)or(dep=l+1)thenbegin ifrest=0theninc(tot); exit; end; fori: =0torestdivpr[dep]do try(dep+1,rest-pr[dep]*i); end; 思路三: 可使用动态规划求解 USACO1.2moneysystem V个物品,背包容量为n,求放法总数。 转移方程: Procedureupdate; varj,k: integer; begin c: =a; forj: =0tondo ifa[j]>0then fork: =1tondivnowdo ifj+now*k<=ntheninc(c[j+now*k],a[j]); a: =c; end; {main} begin read(now);{读入第一个物品的重量} i: =0;{a[i]为背包容量为i时的放法总数} whilei<=ndobegin a[i]: =1;inc(i,now);end;{定义第一个物品重的整数倍的重量a值为1,作为初值} fori: =2tovdo begin read(now); update;{动态更新} end; writeln(a[n]); 7.排序算法 A.快速排序: proceduresort(l,r: integer); vari,j,mid: integer; begin i: =l;j: =r;mid: =a[(l+r)div2];{将当前序列在中间位置的数定义为中间数} repeat whilea[i] whilemid ifi<=jthenbegin{若找到一组与排序目标不一致的数对则交换它们} swap(a[i],a[j]); inc(i);dec(j);{继续找} end; untili>j; ifl ifi end;{sort} B.插入排序: procedureinsert_sort(k,m: word);{k为当前要插入的数,m为插入位置的指针} vari: word;p: 0..1; begin p: =0; fori: =mdownto1do ifk=a[i]thenexit; repeat Ifk>a[m]thenbegin a[m+1]: =k;p: =1; end elsebegin a[m+1]: =a[m];dec(m); end; untilp=1; end;{insert_sort} l主程序中为: a[0]: =0; forI: =1tondoinsert_sort(b[I],I-1); C.选择排序: proceduresort; vari,j,k: integer; begin fori: =1ton-1dobegin k: =i; forj: =i+1tondo
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 常用 100 经典 算法