c语言算法大全.docx

上传人:b****7 文档编号:26259996 上传时间:2023-06-17 格式:DOCX 页数:78 大小:26.90KB
下载 相关 举报
c语言算法大全.docx_第1页
第1页 / 共78页
c语言算法大全.docx_第2页
第2页 / 共78页
c语言算法大全.docx_第3页
第3页 / 共78页
c语言算法大全.docx_第4页
第4页 / 共78页
c语言算法大全.docx_第5页
第5页 / 共78页
点击查看更多>>
下载资源
资源描述

c语言算法大全.docx

《c语言算法大全.docx》由会员分享,可在线阅读,更多相关《c语言算法大全.docx(78页珍藏版)》请在冰豆网上搜索。

c语言算法大全.docx

c语言算法大全

C语言算法大全(C,C++)

一、数论算法

1.求两数的最大公约数

function

gcd(a,b:

integer):

integer;

begin

if

b=0

then

gcd:

=a

else

gcd:

=gcd

(b,a

mod

b);

end

;

2.求两数的最小公倍数

function

lcm(a,b:

integer):

integer;

begin

if

a

then

swap(a,b);

lcm:

=a;

while

lcm

mod

b>0

do

inc(lcm,a);

end;

3.素数的求法

A.小范围内判断一个数是否为质数:

function

prime

(n:

integer):

Boolean;

var

I:

integer;

begin

for

I:

=2

to

trunc(sqrt(n))

do

if

n

mod

I=0

then

begin

prime:

=false;

exit;

end;

prime:

=true;

end;

B.判断

longint范围内的数是否为素数(包含求

50000以内的素数表):

procedure

getprime;

var

i,j:

longint;

p:

array[1..50000]

of

boolean;

begin

fillchar(p,sizeof(p),true);

p[1]:

=false;

i:

=2;

while

i<50000

do

begin

if

p[i]

then

begin

j:

=i*2;

while

j<50000

do

begin

p[j]:

=false;

inc(j,i);

end;

end;

inc(i);

end;

l:

=0;

for

i:

=1

to

50000

do

if

p[i]

then

begin

inc(l);pr[l]:

=i;

end;

end;{getprime}

function

prime(x:

longint):

integer;

var

i:

integer;

begin

prime:

=false;

for

i:

=1

to

ldo

if

pr[i]>=x

then

break

else

if

x

mod

pr[i]=0

then

exit;

prime:

=true;

end;{prime}

 

二、图论算法

1.最小生成树

A.Prim算法:

procedure

prim(v0:

integer);

var

lowcost,closest:

array[1..maxn]

of

integer;

i,j,k,min:

integer;

begin

for

i:

=1

to

n

do

begin

lowcost[i]:

=cost[v0,i];

closest[i]:

=v0;

end;

for

i:

=1

to

n-1

do

begin

{寻找离生成树最近的未加入顶点

k}

min:

=maxlongint;

for

j:

=1

to

n

do

if

(lowcost[j]

and

(lowcost[j]<>0)

then

begin

min:

=lowcost[j];

k:

=j;

end;

lowcost[k]:

=0;

{将顶点

k加入生成树

}

{生成树中增加一条新的边

k到

closest[k]}

{修正各点的

lowcost和

closest值}

for

j:

=1

to

n

do

if

cost[k,j]

then

begin

lowcost[j]:

=cost[k,j];

closest[j]:

=k;

end;

end;

end;{prim}

B.Kruskal算法:

(贪心)

按权值递增顺序删去图中的边,若不形成回路则将此边加入最小生成树。

function

find(v:

integer):

integer;

{返回顶点

v所在的集合

}

var

i:

integer;

begin

i:

=1;

while

(i<=n)

and

(not

v

in

vset[i])

do

inc(i);

if

i<=n

then

find:

=i

else

find:

=0;

end;

procedure

kruskal;

var

tot,i,j:

integer;

begin

for

i:

=1

to

n

do

vset[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条边的长度

}

while

p>0

do

begin

i:

=find(e[q].v1);j:

=find(e[q].v2);

if

i<>jthen

begin

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]

of

integer;

b:

array[1..maxn]

of

integer;

{b[i]指顶点

i到源点的最短路径

}

mark:

array[1..maxn]

of

boolean;

procedure

bhf;

var

best,best_j:

integer;

begin

fillchar(mark,sizeof(mark),false);

mark[1]:

=true;

b[1]:

=0;{1为源点}

repeat

best:

=0;

for

i:

=1

to

n

do

If

mark[i]

then

{对每一个已计算出最短路径的点

}

for

j:

=1

to

n

do

if

(not

mark[j])

and

(a[i,j]>0)

then

if

(best=0)

or

(b[i]+a[i,j]

then

begin

best:

=b[i]+a[i,j];

best_j:

=j;

end;

if

best>0

then

begin

b[best_j]:

=best;mark[best_j]:

=true;

end;

until

best=0;

end;{bhf}

B.Floyed算法求解所有顶点对之间的最短路径:

procedure

floyed;

begin

for

I:

=1

to

n

do

for

j:

=1

to

n

do

if

a[I,j]>0

then

p[I,j]:

=I

else

p[I,j]:

=0;

{p[I,j]表示

I到

j的最短路径上

j的前驱结点

}

for

k:

=1

to

n

do

{枚举中间结点

}

for

i:

=1

to

n

do

for

j:

=1

to

n

do

if

a[i,k]+a[j,k]

then

begin

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]

of

integer;

b,pre:

array[1..maxn]

of

integer;

{pre[i]指最短路径上

I的前驱结点

}

mark:

array[1..maxn]

of

boolean;

procedure

dijkstra(v0:

integer);

begin

fillchar(mark,sizeof(mark),false);

for

i:

=1

to

n

do

begin

d[i]:

=a[v0,i];

if

d[i]<>0

then

pre[i]:

=v0

else

pre[i]:

=0;

end;

mark[v0]:

=true;

repeat{每循环一次加入一个离

1集合最近的结点并调整其他结点的参数

}

min:

=maxint;

u:

=0;

{u记录离

1集合最近的结点

}

for

i:

=1

to

n

do

if

(not

mark[i])

and

(d[i]

then

begin

u:

=i;

min:

=d[i];

end;

if

u<>0

then

begin

mark[u]:

=true;

for

i:

=1

to

n

do

if

(not

mark[i])

and

(a[u,i]+d[u]

then

begin

d[i]:

=a[u,i]+d[u];

pre[i]:

=u;

end;

end;

until

u=0;

end;

3.计算图的传递闭包

Procedure

Longlink;

Var

T:

array[1..maxn,1..maxn]

of

boolean;

Begin

Fillchar(t,sizeof(t),false);

For

k:

=1

to

n

do

For

I:

=1

to

n

do

For

j:

=1

to

n

do

T[I,j]:

=t[I,j]

or

(t[I,k]

and

t[k,j]);

End;

4.无向图的连通分量

A.深度优先

procedure

dfs

now,color:

integer);

begin

for

i:

=1

to

n

do

if

a[now,i]

and

c[i]=0

then

begin

{对结点

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由表示,则

Ee[I]

=

Ve[j];

d.边活动最晚开始时间

El[I],若边

I由表示,则

El[I]

=

Vl[k]

w[j,k];

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条边。

procedure

bellman-ford

begin

for

I:

=0

to

n-1

do

d[I]:

=+infinitive;

d[0]:

=0;

for

I:

=1

to

n-1

do

for

j:

=1

to

m

do

{枚举每一条边

}

if

d[x[j]]+t[j]

then

d[y[j]]:

=d[x[j]]+t[j];

for

I:

=1

to

m

do

if

d[x[j]]+t[j]

then

return

false

else

return

true;

end;

10.第

n最短路径问题

*第二最短路径:

每举最短路径上的每条边,每次删除一条,然后求新图的最短路径,取这

些路径中最短的一条即为第二最短路径。

*同理,第

n最短路径可在求解第

n-1最短路径的基础上求解。

 

三、背包问题

*部分背包问题可有贪心法求解:

计算

Pi/Wi

数据结构:

w[i]:

i个背包的重量;

p[i]:

i个背包的价值;

1.0-1背包:

每个背包只能使用一次或有限次

(可转化为一次

):

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

NOIP2001装箱问题

有一个箱子容量为

v(正整数,

o≤v≤20000),同时有

n个物品(o≤n≤30),每个物品有一个体积

(正整数)。

要求从

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

l搜索方法

procedure

search(k,v:

integer);

{搜索第

k个物品,剩余空间为

v}

var

i,j:

integer;

begin

if

v

then

best:

=v;

if

v-(s[n]-s[k-1])>=best

then

exit;

{s[n]为前

n个物品的重量和

}

if

k<=n

then

begin

if

v>w[k]

then

search(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.

For

I:

=1

to

n

do

For

j:

=w[I]

to

v

do

F[I,j]:

=f[I-1,j-w[I]];

优化:

当前状态只与前一阶段状态有关,可降至一维。

F[0]:

=true;

For

I:

=1

to

n

do

begin

F1:

=f;

For

j:

=w[I]

to

v

do

If

f[j-w[I]]

then

f1[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:

Procedure

update;

var

j,k:

integer;

begin

c:

=a;

for

j:

=0

to

n

do

if

a[j]>0

then

if

j+now<=n

then

inc(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..

jdiv

w[I])

 

B.求可以放入的最大价值。

USACO

1.2

Score

Inflation

 

进行一次竞赛,总时间

T固定,有若干种可选择的题目,每种题目可选入的数量不限,每

种题目有一个

ti(解答此题所需的时间)和一个

si(解答此题所得的分数),现要选择若干

题目,使解这些题的总时间在

T以内的前提下,所得的总分最大,求最大的得分。

*易想到:

f[i,j]

=

max

{

f

[i-k*w[j],

j-1]

+

k*p[j]

}

(0<=k<=

idiv

w[j])

其中

f[i,j]表示容量为

i时取前

j种背包所能达到的最大值。

*实现:

Begin

FillChar(f,SizeOf(f),0);

For

i:

=1

ToM

Do

For

j:

=1

ToN

Do

If

i-problem[j].time>=0

Then

Begin

t:

=problem[j].point+f[i-problem[j].time];

If

t>f[i]

Then

f[i]:

=t;

End;

Writeln(f[M]);

End.

C.求恰好装满的情况数。

Ahoi2001

Problem2

求自然数

n本质不同的质数和的表达式的数目。

思路一,生成每个质数的系数的排列,在一一测试,这是通法。

procedure

try(dep:

integer);

var

i,j:

integer;

begin

cal;

{此过程计算当前系数的计算结果,

now为结果}

if

now>n

then

exit;

{剪枝}

if

dep=l+1

then

begin

{生成所有系数

}

cal;

if

now=n

then

inc(tot);

exit;

end;

for

i:

=0

to

n

div

pr[dep]

do

begin

xs[dep]:

=i;

try(dep+1);

xs[dep]:

=0;

end;

end;

思路二,递归搜索效率较高

procedure

try(dep,rest:

integer);

var

i,j,x:

integer;

begin

 

if

(rest<=0)

or

(dep=l+1)

then

begin

if

rest=0

then

inc(tot);

exit;

end;

for

i:

=0

to

rest

div

pr[dep]

do

try(dep+1,rest-pr[dep]*i);

end;

{main:

try(1,n);}

思路三:

可使用动态规划求解

USACO1.2

money

system

V个物品,背包容量为

n,求放法总数。

转移方程:

Procedure

update;

var

j,k:

integer;

begin

c:

=a;

for

j:

=0

to

n

do

if

a[j]>0

then

for

k:

=1

to

n

div

now

do

if

j+now*k<=n

then

inc(c[j+now*k],a[j]);

a:

=c;

end;

{main}

begin

read(now);{读入第一个物品的重量

}

i:

=0;

{a[i]为背包容量为

i时的放法总数

}

while

i<=n

do

begin

a[i]:

=1;

inc(i,now);

end;{定义第一个物品重的整数倍的重量

a值为

1,作为初值

}

for

i:

=2

to

v

do

begin

read(now);

update;

{动态更新}

end;

writeln(a[n]);

四、排序算法

A.快速排序:

procedure

qsort(l,r:

integer);

var

i,j,mid:

integer;

begin

i:

=l;j:

=r;

mid:

=a[(l+r)

div

2];{将当前序列在中间位置的数定义为中间数

}

repeat

while

a[i]

do

inc(i);

{在左半部分寻找比中间数大的数

}

while

a[j]>mid

do

dec(j);{在右半部分寻找比中间数小的数

}

if

i<=jthen

begin

{若找到一组与排序目标不一致的数对则交换它们

}

swap(a[i],a[j]);

inc(i);dec(j);

{继续找}

end;

until

i>j;

if

l

then

qsort(l,j);{若未到两个数的边界,则递归搜索左右区间

}

if

i

then

qsor

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

当前位置:首页 > 求职职场 > 自我管理与提升

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

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