基本算法.docx

上传人:b****5 文档编号:12055263 上传时间:2023-04-16 格式:DOCX 页数:49 大小:33.19KB
下载 相关 举报
基本算法.docx_第1页
第1页 / 共49页
基本算法.docx_第2页
第2页 / 共49页
基本算法.docx_第3页
第3页 / 共49页
基本算法.docx_第4页
第4页 / 共49页
基本算法.docx_第5页
第5页 / 共49页
点击查看更多>>
下载资源
资源描述

基本算法.docx

《基本算法.docx》由会员分享,可在线阅读,更多相关《基本算法.docx(49页珍藏版)》请在冰豆网上搜索。

基本算法.docx

基本算法

基本算法:

1.数论算法

(1)求两数的最大公约数

functiongcd(a,b:

integer):

integer;

begin

ifb=0thengcd:

=a

elsegcd:

=gcd(b,amodb);

end;

(2)求两数的最小公倍数

functionlcm(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以内的素数表):

var

s:

array[1..maxn]ofboolean;

begin

fillchar(s,sizeof(s),true);

s[1]:

=false;

fori:

=2tomaxndo

ifs[i]then

begin

j:

=i+i;

whilej<=maxndo

begin

s[j]:

=false;

j:

=j+i;

end;

end;

end.

(4)判断因数的个数

varn,nums,k,i:

longint;

begin

k:

=trunc(sqrt(n));

nums:

=2;

fori:

=2tokdo

ifnmodi=0thennums:

=nums+2;

ifn=sqr(k)thendec(nums);

writeln('nums:

',nums);

end.

(5)分解质因数:

k<=maxlongint;

procedureex3(k:

longint);

var

i,j,t:

longint;

s,u:

array[1..50000]oflongint;

begin

fillchar(s,sizeof(s),0);

fillchar(u,sizeof(u),0);

ex2;//筛出50000以内素数、假设一共L个,存于p数组

t:

=k;

j:

=0;

fori:

=1toLdo

begin

iftmodp[i]=0then

begin

inc(j);

s[j]:

=p[i];

end;

whiletmodp[i]=0do

begin

inc(u[j]);

t:

=tdivp[i];

end;

ift=1thenbreak;

end;

ift<>1then

begin

inc(j);

s[j]:

=t;

u[j]:

=1;{大于50000的因子如果它不是素数一定会在前面的过程中被分解,

end;所以剩下的一定是素数}

end;

(6)欧拉函数(求小于等于N的与N互质的数):

Euler函数通式:

φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1,p2……pn为x的所有质因数,x是不为0的整数。

φ

(1)=1(唯一和1互质的数就是1本身)。

若n是质数p的k次幂,φ(n)=p^k-p^(k-1)=(p-1)p^(k-1),因为除了p的倍数外,其他数都跟n互质。

欧拉函数是积性函数——若m,n互质,φ(mn)=φ(m)φ(n)。

特殊性质:

当n为奇数时,φ(2n)=φ(n),证明与上述类似。

functionex4(n:

longint):

longint;

var

i,j,k:

longint;

begin

ex2;

ex3(n);

j:

=ex3中的j;

ex4:

=1;

fori:

=1tojdo

begin

ex4:

=ex4*(s[j]-1);

fork:

=1tou[j]-1do

ex4:

=ex4*s[j];

end;

end;

(7)求一个数的约数个数:

functionex5(n:

longint):

longint;

var

i,j,k:

longint;

begin

ex2;

ex3(n);

j:

=ex3中的j;

ex5:

=1;

fori:

=1tojdo

ex5:

=ex5*(u[i]+1);

ex5:

=ex5-1;

end;

(8)快速幂、取模:

求a^pmodt

functionex6(a,p,t:

longint):

longint;

var

i,j,k,q:

longint;

begin

q:

=p;

k:

=a;

ex6:

=1;

whileq>0do

begin

ifqand1>0then

ex6:

=ex6*kmodt;

k:

=k*kmodt;

q:

=qshr1;

end;

end;

(9).快速幂

functionf(a,b,n):

longint;

var

t,y:

longint;

begin

t=1;y=a;

whileb<>0do

begin

  if(band1)=1thent:

=t*ymodn;

  y:

=y*ymodn;

  b:

=bshr1;

end;

exit(t);

end;

原理:

把b转换成2进制数

该2进制数第i位的权为a^2^(i-1)

例如

a^11=a^(2^0+2^1+2^3)

(6)高精快速幂

高精度快速幂

//以麦森数为例,麦森数位数计算方法trunc(ln

(2)/ln(10)*n)+1

programmaisen(求2^n-1最后500位);

procedurework(n:

longint);//高精度快速幂主过程

var

i,j:

integer;

begin

ifn=1thenyy[1]:

=2

else

begin

work(ndiv2);

fori:

=1to500do

s[i]:

=0;

fori:

=1to500do

forj:

=1to500do

s[i+j-1]:

=s[i+j-1]+yy[i]*yy[j];

ifnmod2=1then

fori:

=1to500do

s[i]:

=s[i]*2;

fori:

=1to500do

begin

s[i+1]:

=s[i+1]+s[i]div10;

s[i]:

=s[i]mod10;

end;

yy:

=s;

end;

end;

(7).几种常见题型

A.筛法求质因数

var

s:

array[1..maxn]ofboolean;

begin

fillchar(s,sizeof(s),true);

s[1]:

=false;

fori:

=2tomaxndo

ifs[i]then

begin

j:

=i+i;

whilej<=maxndo

begin

s[j]:

=false;

j:

=j+i;

end;

end;//截止到此为筛法求素数

m:

=0;

fori:

=2tomaxndo

ifs[i]thenbegin

count:

=0;

repeat

r:

=nmods[i];

ifr=0thenbegin

n:

=ndivs[i];

count:

=count+1;

end;

untilr<>0;

ifcount<>0thenbegin

m:

=m+1;a[m]:

=s[i];b[m]:

=count;

end;

end;

end.

B.欧拉函数(求小于n的且与n互质的数的个数)

//上接筛法求质因数:

即已求得n的各素因数

a:

=n;

fori:

=1tomdo

a:

=a*(a[m]-1);

b:

=1;

fori:

=1tomdo

b:

=b*a[m];

ans:

=adivb;

C.数的拆分

数的所有拆分方法

vart,n:

integer;

a,b:

array[1..1000]ofinteger;

proceduretry(m,start,k:

integer);

vari,j:

integer;

begin

fori:

=startto(mdiv2)do{优化了一下,因为不可能到达N,拆分了只会到达这个数的一半}

begin

a[k]:

=m-i;{减去拆出来的这个数}

t:

=t+1;{有了一种情况,计数}

try(a[k],i,k+1);{在再拆过的这个数上再拆,直到不能拆为止}

end;

end;

begin

readln(n);

try(n,1,1);

writeln(t);

end.

如果把结果打出来是这样的,其实每个人的方法都不一样

N=7

7=1+6

7=1+1+5

7=1+1+1+4

7=1+1+1+1+3

7=1+1+1+1+1+2

7=1+1+1+1+1+1+1

7=1+1+1+2+2

7=1+1+2+3

7=1+2+4

7=1+2+2+2

7=1+3+3

7=2+5

7=2+2+3

7=3+4

D.非零自然数的倒数分解问题

1/16=1/48+1/241/18=1/54+1/27  1/24=1/72+1/36    1/19=1/380+1/20

由于每个倒数分解后第分数的分子都是1,因此只需要考虑第二个分数能不能通过约分使分子为1。

这些分数的分子都是2,明显能分别与16、18、24约分得1。

换句话说,16、18、24都含有因数2。

更进一步说,就是只要分解出来的分数分子是分母的因数,就可实现把这个分数写成某个自然数的倒数的形式。

思考:

要对这些倒数进行分解,首先应搞清楚分母有哪些因数,也就是要对分母分解质因数,进而找出其包含的因数。

比如:

16=2×2×2×2。

它的因数有2、4、8、16四个,那么1/16的分子分母 同乘3、5、9或17都能转换成分子为1的两个分数和的形式。

例如19是质数,只有1和19两个因数,于是1/19=20/(19×20)=1/380+1/20。

归纳上述解题过程,我们得出自然数倒数分解的几个步骤:

1、找出分母的某个因数m;2、分子分母同乘m+1;3、把新得到的分数分解成两个分数的和;4、对分子为m的分数进行约分

  上述过程可以用代数的形式表示:

设m是非零自然数p的一个因数,那么一定存在另一因数n,使得p=mn,从而1/p=(m+1)/p(m+1)=1/(p(m+1)+m/p(m+1)=1/p(m+1)+1/n(m+1)。

当m=1时,n=p,由上式知1/p=1/2p+1/2p,不符合要求。

因此在没有特别说明的情况下,以后所讲因数均不含1。

既然m、n都是p的因数,那么把1/p分解成分子分别是m和n的两个分数,然后约分也可得到符合条件的分解。

1/p=(m+n)/p(m+n)=m/(p(m+n)+n/p(m+n)=1/n(m+n)+1/m(m+n)。

至些,我们发现,只要m、n是p的因数,即便p≠mn,上式仍然成立。

 

  结论:

①任何大于1的自然数的倒数都可以分解成其他两具不同自然数的倒数和的形式。

②将非零自然的倒数分解成其他两个不同自然数的倒数和,其方法的多少是由这个自然数的因数的个数决定的。

③推论:

任何非零自然的倒数可以表示为任意多个其他自然数的倒数和的形式。

E.高精运算

【题目】数学上定义:

n!

=1×2×3×...×(n-1)×n(N>0)

0!

=1

若用integer型数据表示阶乘,最多可到7!

用Longint类型也只能到12!

要求输入正整数n,求n!

的精确表示

【算法分析】用数组存放结果,模拟人工计算过程,逐位去乘,注意进位情况的处理。

vara:

array[1..10000]ofinteger;

b,c,d,t,x:

integer;

begin

write('inputnumber:

');

readln(x);

if(x<0)thenbeginwriteln('error!

');readln;halt;end;

fort:

=1to10000doa[t]:

=0;

d:

=1;a[1]:

=1;

forc:

=1toxdo{一直乘到x}

begin

t:

=1;b:

=0;{t:

第几位数b:

进位d:

总位数}

repeat

a[t]:

=a[t]*c+b;{数组每位均乘上c,同时加上进位}

b:

=a[t]div10;{分离出进位}

ifa[t]>=10thenif(t=d)thend:

=d+1;{假如最后一位乘时有}

{进位,则总位数加1}

a[t]:

=a[t]mod10;

inc(t);{数组下一位}

until(t>d);{直到乘完数组的每一位数字}

end;

write(x,'!

=');

fort:

=ddownto1dowrite(a[t]);{输出}

end.

F.万年历问题

【题目】输入年、月、日,求这一天是星期几。

【参考程序1】

【算法提要】求出这一天离公元1年的元旦有多少天days,然后对7求余

const

first=1;{公元1年为基准}

first_week=1;{公元1年的元旦为星期一}

yue:

array[1..12]of1..31=(31,28,31,30,31,30,31,31,30,31,30,31);

week_:

array[0..6]ofstring[20]=('Sunday','Monday','Tuesday','Wedsday',

'Thursday','Friday','Saturday');

var

days,week,year,month,date,i,years:

longint;

begin

writeln('year:

');readln(year);

writeln('month');readln(month);

writeln('date');readln(date);

years:

=0;days:

=0;

fori:

=firsttoyear-1do

if(imod400=0)or(imod4=0)and(imod100<>0)then

beginyears:

=years+1;end;{注意处理闰年的情况}

days:

=(year-first)*365+years;{离基准年过了多少天}

fori:

=1tomonth-1dodays:

=days+yue[i];{本年过了多少个月}

fori:

=1todatedodays:

=days+1;{本月过了多少天}

if((yearmod400=0)or(yearmod4=0)and(yearmod100<>0))

and(month>3)thendays:

=days+1;{如果本年为闰年,且月份超2月,还要考虑加1}

week:

=((days-1)mod7+first_week)mod7;{求星期数}

writeln('itis',week_[week]);

readln;

end.

【参考程序2】用公式法:

days:

=trunc((year-1)*(1+1/4-1/100+1/400)+c)

用求出的days对7求余数。

其中c为该天离该年元旦的天数

const

first=1;

first_week=1;

yue:

array[1..12]of1..31=(31,28,31,30,31,30,31,31,30,31,30,31);

week_:

array[0..6]ofstring[20]=('Sunday','Monday','Tuesday','Wedsday',

'Thursday','Friday','Saturday');

var

days,week,year,month,date,i:

longint;

begin

writeln('year:

');readln(year);

writeln('month');readln(month);

writeln('date');readln(date);

days:

=0;

fori:

=1tomonth-1dodays:

=days+yue[i];

fori:

=1todatedodays:

=days+1;

if((yearmod400=0)or(yearmod4=0)and(yearmod100<>0))

and(month>3)thendays:

=days+1;

days:

=trunc((year-1)*(1+1/4-1/100+1/400)+days);

week:

=daysmod7;

writeln('itis',week_[week]);

readln;

end.

2.求最小生成树

见课本

3.最短路径

见课本

4.0-1背包问题(部分背包问题可有贪心法求解:

计算Pi/Wi)

数据结构:

w[i]:

第i个背包的重量;

p[i]:

第i个背包的价值;

(1)0-1背包:

每个背包只能使用一次或有限次(可转化为一次):

A.求最多可放入的重量。

NOIP2001装箱问题

有一个箱子容量为v(正整数,o≤v≤20000),同时有n个物品(o≤n≤30),每个物品有一个体积(正整数)。

要求从n个物品中,任取若千个装入箱内,使箱子的剩余空间为最小。

多重背包:

procedureMultiplePack(cost,weight,amount)

ifcost*amount>=V

CompletePack(cost,weight)

return

integerk=1

whilek

ZeroOnePack(k*cost,k*weight)

amount=amount-k

k=k*2

ZeroOnePack(amount*cost,amount*weight)

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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 党团工作 > 其它

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1