c算法大全常用c语言算法包括数论算法图论算法排序算法高精度计算树的遍历算法等等.docx
- 文档编号:6836076
- 上传时间:2023-01-11
- 格式:DOCX
- 页数:20
- 大小:25.51KB
c算法大全常用c语言算法包括数论算法图论算法排序算法高精度计算树的遍历算法等等.docx
《c算法大全常用c语言算法包括数论算法图论算法排序算法高精度计算树的遍历算法等等.docx》由会员分享,可在线阅读,更多相关《c算法大全常用c语言算法包括数论算法图论算法排序算法高精度计算树的遍历算法等等.docx(20页珍藏版)》请在冰豆网上搜索。
c算法大全常用c语言算法包括数论算法图论算法排序算法高精度计算树的遍历算法等等
一、数论算法
1.求两数的最大公约数
function gcd(a,b:
integer):
integer;
begin
ifb=0thengcd:
=a
elsegcd:
=gcd(b,amodb);
end;
2.求两数的最小公倍数
function lcm(a,b:
integer):
integer;
begin
ifa lcm: =a; whilelcmmodb>0doinc(lcm,a); end; 3.素数的求法 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} 二、图论算法 1.最小生成树 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 if cost[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; 2.最短路径 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; 3.计算图的传递闭包 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; 4.无向图的连通分量 A.深度优先 proceduredfs(now,color: integer); begin fori: =1tondo ifa[now,i]andc[i]=0thenbegin{对结点I染色} c[i]: =color; dfs(I,color); end; end; B宽度优先(种子染色法) 5.关键路径 几个定义: 顶点1为源点,n为汇点。 a.顶点事件最早发生时间Ve[j],Ve[j]=max{Ve[j]+w[I,j]},其中Ve (1)=0; b.顶点事件最晚发生时间Vl[j],Vl[j]=min{Vl[j]–w[I,j]},其中Vl(n)=Ve(n); c.边活动最早开始时间Ee[I],若边I由 d.边活动最晚开始时间El[I],若边I由 若Ee[j]=El[j],则活动j为关键活动,由关键活动组成的路径为关键路径。 求解方法: a.从源点起topsort,判断是否有回路并计算Ve; b.从汇点起topsort,求Vl; c.算Ee和El; 6.拓扑排序 找入度为0的点,删去与其相连的所有边,不断重复这一过程。 例 寻找一数列,其中任意连续p项之和为正,任意q项之和为负,若不存在则输出NO. 7.回路问题 Euler回路(DFS) 定义: 经过图的每条边仅一次的回路。 (充要条件: 图连同且无奇点) Hamilton回路 定义: 经过图的每个顶点仅一次的回路。 一笔画 充要条件: 图连通且奇点个数为0个或2个。 9.判断图中是否有负权回路Bellman-ford算法 x[I],y[I],t[I]分别表示第I条边的起点,终点和权。 共n个结点和m条边。 procedurebellman-ford begin forI: =0ton-1dod[I]: =+infinitive; d[0]: =0; forI: =1ton-1do forj: =1tomdo{枚举每一条边} ifd[x[j]]+t[j] =d[x[j]]+t[j]; forI: =1tomdo ifd[x[j]]+t[j] end; 10.第n最短路径问题 *第二最短路径: 每举最短路径上的每条边,每次删除一条,然后求新图的最短路径,取这些路径中最短的一条即为第二最短路径。 *同理,第n最短路径可在求解第n-1最短路径的基础上求解。 [color=#0000FF]三、背包问题[/color] *部分背包问题可有贪心法求解: 计算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]tovdo F[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]为容量为I时取前j个背包所能获得的最大价值。 F[i,j]=max{f[i–w[j],j-1]+p[j], f[i,j-1]} C.求恰好装满的情况数。 DP: Procedureupdate; varj,k: integer; begin c: =a; forj: =0tondo ifa[j]>0then ifj+now<=ntheninc(c[j+now],a[j]); a: =c; end; 2.可重复背包 A求最多可放入的重量。 F[I,j]为前i个物品中选择若干个放入使其体积正好为j的标志,为布尔型。 状态转移方程为 f[I,j]=f[I-1,j–w[I]*k](k=1..jdivw[I]) B.求可以放入的最大价值。 USACO1.2 ScoreInflation 进行一次竞赛,总时间T固定,有若干种可选择的题目,每种题目可选入的数量不限,每种题目有一个ti(解答此题所需的时间)和一个si(解答此题所得的分数),现要选择若干题目,使解这些题的总时间在T以内的前提下,所得的总分最大,求最大的得分。 *易想到: f[i,j]=max{f[i-k*w[j],j-1]+k*p[j]} (0<=k<=idivw[j]) 其中f[i,j]表示容量为i时取前j种背包所能达到的最大值。 *实现: Begin 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; Writeln(f[M]); 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] do begin 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; {main: try(1,n);} 思路三: 可使用动态规划求解 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]); 四、排序算法 1.快速排序: procedureqsort(l,r: integer); vari,j,mid: integer; begin i: =l;j: =r;mid: =a[(l+r)div2];{将当前序列在中间位置的数定义为中间数} repeat whilea[i] whilea[j]>middodec(j);{在右半部分寻找比中间数小的数} ifi<=jthenbegin {若找到一组与排序目标不一致的数对则交换它们} swap(a[i],a[j]); inc(i);dec(j); {继续找} end; untili>j; ifl ifi end;{sort} B.插入排序: 思路: 当前a[1]..a[i-1]已排好序了,现要插入a[i]使a[1]..a[i]有序。 procedureinsert_sort; vari,j: integer; begin fori: =2tondobegin a[0]: =a[i]; j: =i-1; whilea[0] a[j+1]: =a[j]; j: =j-1; end; a[j+1]: =a[0]; end; end;{inset_sort} C.选择排序: proceduresort; vari,j,k: integer; begin fori: =1ton-1do forj: =i+1tondo ifa[i]>a[j]thenswap(a[i],a[j]); end; D.冒泡排序 procedurebubble_sort; vari,j,k: integer; begin fori: =1ton-1do forj: =ndowntoi+1do ifa[j] end; E.堆排序: proceduresift(i,m: integer);{调整以i为根的子树成为堆,m为结点总数} var
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 大全 常用 语言 包括 数论 排序 高精度 计算 遍历 等等