c++常用简单算法与技巧Word格式.docx
《c++常用简单算法与技巧Word格式.docx》由会员分享,可在线阅读,更多相关《c++常用简单算法与技巧Word格式.docx(31页珍藏版)》请在冰豆网上搜索。
//计数器初值一般为0
for(i=1;
i<
=n;
i++){
cin>
if(a%2==0)j=j+1;
//每次用自身加上1再赋给自身,即j++
j;
6、累加器
s=0;
//累加器的初值一般为0
s=s+a;
//将新数加上自身再赋给自身
s=s+a;
s;
7、累乘器
s=1;
//累乘器的初值一般为1
s=s*a;
//将新数乘上自身在赋给自身
s=s*a;
8、标记法(求素数)
输入整数n,请判断其是否为质数。
f=1;
//用f做标记,为1则表示是素数
for(j=2;
j<
j++)
if(n%j==0)f=0;
//f为0,则表示n在2~n-1之间有一个约数
if(f==1)cout<
elsecout<
9、求最大值
先假设输入的第一个数即为最大数,然后用它去和后面的数一一进行比较,如果后面的数比它大,则将大的数交换给它。
max=a;
i++)
{cin>
if(a>
max)max=a;
10、求最小值
先假设输入的第一个数即为最小数,然后用它去和后面的数一一进行比较,如果后面的数比它小,则将小的数交换给它。
min=a;
if(a<
min)min=a;
11、字符的处理
出入一串字母和数字,以”.“号结束,统计其中字母和数字的个数。
zimu=0;
shuzi=0;
for(cin>
a!
=’.’;
=’a’&
&
a<
=’z’||a>
=’A’&
=’Z’)zimu++;
=’0’&
=’9’)shuzi++;
输入一串小写字母,以”.“号结束,输出字母所对应的数字,规定a对应数字1,b对应数字2,z对应数字26,输出的数字间以空格隔开。
=’z’)n=a-‘a’+1;
cout<
n<
’
‘;
//字母类型的数字要转为对应的整数可以采取同样的办法,
//intn;
chara;
n=a-‘0’;
空格的处理
cin命令做输入时会自动跳过空格和回车等符号,如果要求对空格进行处理则需要用到cin.get(a);
也可以用scanf(“%c”,&
a);
但不能用cin>
12、数学函数库
有一些标准数学函数在信息奥赛中是允许使用的,使用时要加上数学函数库
cmath>
doublea,b,c,d;
c=sqrt(a);
//sqrt为求平方根函数
d=pow(a,b);
//pow为求ab的函数,求平方可以用它,注意它的参数为实数类型
13、求最大公约数
求两自然数m,n的最大公约数。
最大公约数:
能同时被m和n整除的最大数。
如6和4的最大公约数为2
1)欧几里德算法(m>
n)
①m被n除得到余数r(0≤r≤n)
r=m%n
②若r=0,则算法结束,n为最大公约数,否则做3
③m=n,n=r,回到1
使用的是循环迭代的方法
m=6
n=4
r=m%n=6%4=2
m=4
n=2
r=m%n=4%2=0
所以,公约数=2
程序代码:
m>
for(r=m%n;
r!
r=m%n)
{m=n;
n=r;
2)穷举
最大公约数只能是n,n-1,...,2,1中的一个,一一列举出来试一下即可。
for(i=n;
i>
0;
i--)
if(m%i==0&
n%i==0){cout<
i;
return(0);
虽然两种算法都可以求出最大公约数,但执行效率不同,穷举显然循环次数最多,最费时。
比如30002002这两个数,用穷举要执行2001次循环,而欧几里德算法只需要4次,算法的优劣一目了然。
14、求最小公倍数
最小公倍数:
能同时整除m和n的最小数。
1)已知最大公约数时的方法
最小公倍数为两数之积除以最大公约数。
接上例4和6的最小公倍数为4*6/2=12。
2)直接尝试
for(t=m;
m%n!
m=m+t);
m;
将较大数的值放在变量t中,每次用m直接加上t去尝试能否除尽n,如果能,现在的m就是最小公倍数。
大多时候还是应该选择使用第一种方法,仍以30002002为例,用第一种方法只需要4次循环求出最大公约数,然后求出最小公倍数,而第二种方法要执行上千次才能出结果。
15、穷举法
穷举法也称为“枚举法”,这种算法基本思想是依题目的部分条件,确定答案的大致范围;
在此范围
内,对所有可能的情况一一列举,逐一验证,直到全部情况验证完毕,或者得到了需要的结果。
若某个情况经验证符合题目的全部条件,则它就是本题的一个答案;
若全部情况经验证后,都不符合
题目的全部条件,则原题无解。
用穷举法解题的大致步骤如下:
1)分析题目,确定所要求的解是什么?
2)确定解的可能取值范围是什么?
3)穷举出所有可能的解
4)验证每一个可能的解
5)优化
例:
鸡兔同笼问题
一个笼子里有鸡和兔,现在只知道里面一共有a个头,b只脚,问鸡和兔各有多少只(要求鸡和兔至少1只)?
inti,j,a,b;
i++)
//鸡可能为1~a-1只
for(j=1;
j++)
//兔可能为1~a-1只
if(i+j==a&
i*2+j*4==b)cout<
’‘<
endl;
16、递推的思想
迭代的方法
斐波那契数列(从第三项起为前面两项之和)
11235813…
a1=1;
a2=1;
for(i=3;
i<
i++)
a3=a1+a2;
a1=a2;
a2=a3;
a3;
猴子吃桃问题。
猴子摘了一堆桃,第一天吃了一半,还嫌不过瘾,又吃了一个;
第二天又吃了剩下的一半零一个;
以后每天如此。
到第N天,猴子一看只剩下一个了。
问最初有多少个桃子?
for(i=2;
s=(s+1)*2;
17、文件的处理方法
fstream>
usingnamespacestd;
ifstreamfin(“输入文件名”);
ofstreamfout(“输出文件名”);
陶陶摘苹果(文件名:
apple.cpp)
【问题描述】
陶陶家的院子里有一棵苹果树,每到秋天树上就会结出10个苹果。
苹果成熟的时候,陶陶就会跑去摘苹果。
陶陶有个30厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。
现在已知10个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度,请帮陶陶算一下她能够摘到的苹果的数目。
假设她碰到苹果,苹果就会掉下来。
【输入文件】输入文件apple.in包括两行数据。
第一行只包括一个100到120之间(包含100和120)的整数(以厘米为单位),表示陶陶把手伸直的时候能够达到的最大高度。
第二行包含10个100到200之间(包括100和200)的整数(以厘米为单位)分别表示10个苹果到地面的高度,两个相邻的整数之间用一个空格隔开。
【输出文件】输出文件apple.out包括一行,这一行只包含一个整数,表示陶陶能够摘到的苹果的数目。
【样例输入】
110
100200150140129134167198200111
【样例输出】
5
ifstreamfin("
apple.in"
);
ofstreamfout("
apple.out"
intmain(){
intrg,sg,i,j=0;
fin>
rg;
for(i=0;
10;
sg;
if(sg<
=rg+30)j++;
}
fout<
多重循环讲解与练习
for(;
;
)
语句组;
for(;
{
}
1、图形字符类
例1、输出m行n列*号
for(i=0;
i++)//外循环通常用作控制行,表示输出图形有m行
for(j=0;
j++)//内循环通常用作列,表示一行上有多少列字符
‘*’;
外循环i=0时,内循环j从0一直变化到n-1,即内循环中的语句{cout<
}被执行了n次,语句cout<
是外循环中的语句,执行1次。
当外循环的i值变化到m退出时,内循环中的语句{cout<
}一共被执行了m×
n次。
有时每列上的字符个数不同,如
例2、n=3时,输出如下图形
*
**
***
i++)
=i;
有时每列上的字符个数不向上面图形一般每行以1递增,如
例3、n=3时,输出如下图形
*****
for(i=1;
for(j=1;
=2*i-1;
j++)//每行上的字符以2递增,因此是2*i
如果是这样的金字塔形式
例4、n=3,输出
*
可以看作是先输出了一个倒三角形的空格,然后再输出上例中的图形
=n-i;
j++)//每行上的空格数是n-1,n-2,...,1,0这样一个递减序列,而i每次递增1,要将一个递增序列改为递减序列,直接在前面加上-号
'
'
;
练习:
可以尝试打出如下图形:
如n=3,要求输出
***
*
***
**********
***************
a
bbb
ccccc
a
2、逻辑推理题目
解逻辑判断与推理题这类题首先要把复杂的逻辑关系进行分析、抽象、化简,然后进行尝试排除,得到最后结果。
可以用计算机来验证推断的结果,复杂的还可以直接用逻辑表达式来表示各种关系条件,用计算机穷举各种可能情况,再根据条件采取累试排除或选择需要的组合。
【例1】四位同学不知是哪一位打碎了教室窗户的玻璃,老师问是哪一个同学打的。
A说:
“不是我”,B说:
“是C”,C说:
“是D”,D反驳说:
“他胡说!
”。
四个人当中只有一个人说假话,试判断哪一位打碎了教室窗户的玻璃?
分析:
用A,B,C,D分别表示这四位同学,用1表示打碎了玻璃,0表示没有打碎。
题目中四句话可表示成:
A!
=1
C==1
D==1
D!
A,B,C,D只有一位同学打碎了玻璃,因此A+B+C+D的值为1。
逻辑表达式只有1和0两个值,为1表示真,为0表示假,
只有一个人说假话,则说明四个表达式的和应为3。
程序如下:
for(A=0;
A<
2;
A++)
for(B=0;
B<
B++)
for(C=0;
C<
C++)
for(D=0;
D<
D++)if(A+B+C+D==1&
(A!
=1)+(C==1)+(D==1)+(D!
=1)==3)
{if(A==1)cout<
A'
if(B==1)cout<
B'
if(C==1)cout<
C'
if(D==1)cout<
D'
四个循环分别用于穷举A,B,C,D四位同学打碎玻璃和没有打碎玻璃的所有情况,加上判断就可以确定到底是谁打碎了玻璃。
也可以用其他方法来做,尝试一下。
【例2】有四个学生对我国四大淡水湖排列次序如下:
甲:
洞庭湖最大,洪泽湖最小,鄱阳湖第三。
乙:
洞庭湖最小,洪泽湖最大,鄱阳湖第二,太湖第三。
丙:
洞庭湖第三,洪泽湖最小。
丁:
洪泽湖第二,鄱阳湖最大,太湖最小。
每人都只说对了一个,试编程排出正确次序。
用d、h、p、t分别表示洞庭湖、洪泽湖、鄱阳湖、太湖。
四个湖泊的顺序号只能是1、2、3、4的不同组合,所以d+h+p+t=10。
则四个人的话可表示为:
d==1,h==4,p==3
h==1,d==4,p==2,t==3
h==4,d==3
p==1,t==4,h==2,t==3
由于每人都只说对了一个,所以上述表示每个人的观点的式子中只有一个真值为1,其他为0。
程序如下:
for(d=1;
d<
5;
d++)
for(h=1;
h<
h++)
for(p=1;
p<
p++)
for(t=1;
t<
t++)
if((d!
=h)&
(d!
=p)&
=t)&
(h!
(h!
(p!
(d==1)+(h==4)+(p==3)==1&
(d==4)+(h==1)+(p==2)+(t==3)==1&
(d==3)+(h==4)==1&
(h==2)+(p==1)+(t==4)==1)
{cout<
"
dongtinghuis:
hongzehuis:
poyanghuis:
taihuis:
程序写得稍嫌复杂,实际上可以简便一些。
if(d!
=h)
if(p!
=h&
p!
=d)
{t=10-d-h-p;
if((d==1)+(h==4)+(p==3)==1)
if((d==4)+(h==1)+(p==2)+(t==3)==1)
if((d==3)+(h==4)==1)
if((h==2)+(p==1)+(t==4)==1)
循环减少一个,表达式分开写,看起来要清晰些。
(1)某年级数学竞赛中,A、B、C、D、E五位同学获得前五名。
A说:
“D是第一,C是第四”;
B说:
“A是第一,E是第二”;
C说:
“B是第二,D是第三”;
D说:
“E是第三,A是第五”;
E说:
“E是第二,C是第四”。
(2)甲、乙、丙三位同学中有一人趁大家不在教室的时候把教室打扫干净了。
事后老师问是谁做的好事。
甲说:
“是乙做的”,乙说:
“不是我”,丙说:
“不是我”。
三个人当中只有一个人说真话,试判断哪一位做了好事?
(3)有红、黄、蓝、白四色球各一个,放置在编号为1、2、3、4四个格子的盒中,每个格子中只能放一个小球,他们的顺序不知。
甲、乙、丙三人猜测的顺序如下:
蓝色球编号为1,黄色球编号为2;
乙说:
蓝色球编号为2,白色球编号为3;
丙说:
红色球编号为2,白色球编号为4。
结果证明三个人各猜中一半。
问四个格子的盒中放置小球情况。
一维数组讲解与练习
一、为什么要使用数组
学到现在,我们用分支结构解决了计算机的智能判断问题,用循环充分利用了计算机处理速度快的特点,也可以用循环对大量数据进行处理,但这些数据却无法大量保存,在这点上还没有利用上计算机存储容量大的特点。
在程序语言中有一种数据结构可以解决这个问题,那就是数组。
例1、输入1000个学生的某门课程的成绩,打印出低于平均分的同学号数与成绩。
在解决这个问题时,虽然可以通过读入一个数就累加一个数的办法来求学生的总分,进而求出平均分。
但因为只有读入最后一个学生的分数以后才能求得平均分,且要打印出低于平均分的同学,故必须把1000个学生的成绩都保留下来,然后逐个和平均分比较,把高于平均分的成绩打印出来。
如果,用简单变量a1,a2,…,a1000存放这些数据,可想而知程序要很长且繁。
要想如数学中使用下标变量ai形式表示这1000个数,则可以引入下标变量a[i]。
这样问题的程序可写为:
tot=0;
//tot表示总分
=1000;
i++)//环读入每一个学生的成绩,并累加它到总分}
cin>
a[i];
tot:
=tot+a[i];
ave=tot/1000;
//计算平均分
if(a[i]<
ave)cout<
”No.”<
:
//如果第i个同学成绩小于平均分,则将其输出
而要在程序中使用下标变量,则必须先说明这些下标变量的整体——数组,即数组是若干个同名(如上面的下标变量的名字都为a)下标变量的集合。
二、一维数组
1、一维数组的定义和引用
当数组中每个元素只带有一个下标时,我们称这样的数组为一维数组。
数组是同一类型的一组值(10个char、15个int…),在内存中顺序存放。
整个数组共用一个名字,而其中的每一项又称为一个元素。
1)定义方式:
类型说明符
数组名[常量表达式];
int
a[4];
//int是数组元素的类型说明,4表示元素个数,a表示数组名称,整个说明表明a数组由4个int型元素组成,这四个元素分别是:
a[0],a[1],a[2],a[3]
要注意的两个地方:
其序号从0开始,而不是从1开始。
所以inta[4];
实际上不包含a[4]这个元素
C++不允许对数组的大小作动态的定义,即数组的大小不能是变量,必须是常量。
即不能定义为inta[n];
只能是inta[1000];
等,即元素个数必须是确定的。
2)一维数组元素的引用
数组必须先定义,具体引用时(赋值、运算、输出)其元素等同于变量。
数组元素的赋值与输出通常采用的是循环。
例2、输入100个数,将其倒序输出。
intmain()
{
int
i,
a[100];
for(i=0;
100;
for(i=99;
i>
=0;
i--)
a[i]<
‘
’;
3)一维数组的初始化
除了用循环读入处理外,一维数组还可以直接进行赋值操作。
inta,b=0,c[5]={1,2,3,4,5};
此例也可以写成,intc[5];
c[0]=1;
c[1]=2;
c[2]=3;
c[3]=4;
c[4]=5;
注意:
不能给数组整体赋值,只能一个一个地赋值
比如上例写成:
inta,b=0,c[5]={1,2,…,5};
就是错误的。
2、一位数组的应用实例
例3、求Fibonacci数列:
1,1,2,3,5,8,......的前20个数,将它们5个数一行的输出,每两个数之间隔一个制表符的距离。
Fibonacci数列可表示为以下数学递推公式:
F1=1
(n=1)
F2=1
(n=2)
Fn=Fn-1+Fn-2
(n>
=3)
i;
f[21];
f[1]=1;
f[2]=1;
for(i=2;
21;
i++)
f[i]=f[i-1]+f[i-2];
for(i=1;
21;
i++)
{
f[i]<
”\t”;
if(i%5==0)
“\n”;
例4、输入十个正整数,把这十个数按由大到小的顺序排列。
将数据按一定顺序排列称为排序,排序的算法有很多,其中选择排序是一种较简单的方法。
要把十个数按从大到小顺序排列,则排完后,第一个数最大,第二个数次大,……。
因此,我们第一步可将第