绪论:
算法的五大特性:
⑴ 输入:一个算法有零个或多个输入。
⑵ 输出:一个算法有一个或多个输出。
⑶ 有穷性:一个算法必须总是在执行有穷步之后结束,且每一步都在有穷时间内完成。
⑷ 确定性:算法中的每一条指令必须有确切的含义,对于相同的输入只能得到相同的输出。
⑸ 可行性:算法描述的操作可以通过已经实现的基本操作执行有限次来实现。
时间复杂性分析的关键:
问题规模:输入量的多少;
基本语句:执行次数与整个算法的执行时间
成正比的语句
递归算法:
【例1】数字三角形。如下所示为一个数字三角形。请编一个程序计算从顶到底的某处的一条路径,使该路径所经过的数字总和最大。只要求输出总和。
1、 一步可沿左斜线向下或右斜线向下走;
2、 三角形行数小于等于100;
3、 三角形中的数字为0,1,…,99;
测试数据通过键盘逐行输入,如上例数据应以如下所示格式输入:
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
【算法分析】
此题解法有多种,从递推的思想出发,设想,当从顶层沿某条路径走到第i层向第i+1层前进时,我们的选择一定是沿其下两条可行路径中最大数字的方向前进,为此,我们可以采用倒推的手法,设a[i][j]存放从i,j 出发到达n层的最大值,则a[i][j]=max{a[i][j]+a[i+1][j],a[i][j]+a[i+1][j+1]},a[1][1] 即为所求的数字总和的最大值。
#include<iostream>
using namespace std;
int main()
{
int n,i,j,a[101][101];
cin>>n;
for (i=1;i<=n;i++)
for (j=1;j<=i;j++)
cin>>a[i][j]; //输入数字三角形的值
for (i=n-1;i>=1;i--)
for (j=1;j<=i;j++)
{
if (a[i+1][j]>=a[i+1][j+1]) a[i][j]+=a[i+1][j]; //路径选择
else a[i][j]+=a[i+1][j+1];
}
cout<<a[1][1]<<endl;
}
【例2】满足F1=F2=1,Fn=Fn-1+Fn-2的数列称为斐波那契数列(Fibonacci),它的前若干项是1,1,2,3,5,8,13,21,34……求此数 列第n项(n>=3)。
即:
f1=1 (n=1)
f2=1 (n=2)
fn=fn-1 + fn-2 (n>=3)
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int f0=1,f1=1,f2;
int n;
cin>>n;
for (int i=3; i<=n; ++i)
{
f2=f0+f1;
f0=f1;
f1=f2;
}
printf("%d\n",f2);
return 0;
}
【例3】 有 2×n的一个长方形方格,用一个1×2的骨牌铺满方格。
编写一个程序,试对给出的任意一个n(n>0), 输出铺法总数。
【算法分析】
(1)面对上述问题,如果思考方法不恰当,要想获得问题的解答是相当困难的。可以用递推方法归纳出问题解的一般规律。
(2)当n=1时,只能是一种铺法,铺法总数有示为x1=1。
(3)当n=2时:骨牌可以两个并列竖排,也可以并列横排,再无其他方法,如下左图所示,因此,铺法总数表示为x2=2;
(4)当n=3时:骨牌可以全部竖排,也可以认为在方格中已经有一个竖排骨牌,则需要在方格中排列两个横排骨牌(无重复方法),若已经在方格中排列两个横排骨牌,则必须在方格中排列一个竖排骨牌。如上右图,再无其他排列方法,因此铺法总数表示为x3=3。
由此可以看出,当n=3时的排列骨牌的方法数是n=1和n=2排列方法数的和。
(5)推出一般规律:对一般的n,要求xn可以这样来考虑,若第一个骨牌是竖排列放置,剩下有n-1个骨牌需要排列,这时排列方法数为xn-1;若第一个骨牌是横排列,整个方格至少有2个骨牌是横排列(1*2骨牌),因此剩下n-2个骨牌需要排列,这是骨牌排列方法数为xn-2。从第一骨牌排列方法考虑,只有这两种可能,所以有:
xn=xn-1+xn-2 (n>2)
x1=1
x2=2
xn=xn-1+xn-2就是问题求解的递推公式。任给n都可以从中获得解答。例如n=5,
x3=x2+x1=3
x4=x3+x2=5
x5=x4+x3=8
下面是输入n,输出x1~xn的c++程序:
#include<iostream>
using namespace std;
int main()
{
int n,i,j,a[101];
cout<<"input n:"; //输入骨牌数
cin>>n;
a[1]=1;a[2]=2;
cout<<"x[1]="<<a[1]<<endl;
cout<<"x[2]="<<a[2]<<endl;
for (i=3;i<=n;i++) //递推过程
{
a[i]=a[i-1]+a[i-2];
cout<<"x["<<i<<"]="<<a[i]<<endl;
}
}
输出的数组结果即为Fibonacci序列