}
1.1.4测试数据及测试结果
运行程序:
请输入两个正整数:
1812
18与12的最大公约数是:
6
1.1.5算法复杂度分析
时间复杂度分析:
辗转相除法的循环次数与m、n的大小不成正比,∴时间复杂度为O
(1)
空间复杂度分析:
算法在执行过程中临时存储单元为1个(变量r),∴空间复杂度为O
(1)
1.2输出杨辉三角形前n行
1.2.1问题描述
1.2.2算法描述
1.2.3程序设计与实现
1.2.4测试数据及测试结果
1.2.5算法复杂度分析
1.3统计数字问题
1.3.1问题描述
一本书的页码从自然数1开始顺序编码直到自然数n。
书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。
例如,第6页用数字6表示,而不是06或006等。
数字计数问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1,2,…,9。
1.3.2算法分析与设计:
给定表示书的总页码的10进制整数n(1≤n≤109),计算书的全部页码中分别用到多少次数字0,1,2,…,9。
输入数据、输出结果示例
输入数据:
11
输出结果:
数字:
0123456789
用到次数:
1411111111
1.3.3算法描述
1.3.4程序设计与实现
1.3.5测试数据及测试结果
1.3.6算法复杂度分析
1.4最多约数问题
1.4.1问题描述
1.4.2算法分析与设计
1.4.3算法描述
1.4.4程序设计与实现
1.4.5测试数据及测试结果
1.4.6算法复杂度分析
实验2递归与分治
一、实验环境
操作系统:
WindowsXP编程语言:
VisualC++6.0或VS2012
二、实验目的
学习和了解递归与分治算法的概念和基本思想,熟悉对递归与分治问题的分析方法及其适用范围;
掌握递归与分治算法的设计思路和基本步骤,学会使用递归与分治算法解决实际问题。
三、实验内容
2.1求最大最小元问题
2.2归并排序
2.3快速排序
2.4众数问题
2.5*马的Hamilton周游路线问题
四、实验开始
2.1求最大最小元问题
2.1.1问题描述
2.1.2算法分析与设计
2.1.3算法描述
2.1.4程序设计与实现
2.1.5测试数据及测试结果
2.1.6算法复杂度分析
2.2归并排序(MergingSort)
2.2.1问题描述
“归并”的含义是将两个或两个以上的有序表组合成一个新的有序表。
利用归并的思想实现排序。
2-路归并排序:
设初始序列含有n个记录,则可看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2个长度为2或1的有序子序列;再两两归并,……,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2-路归并排序。
2.2.2算法分析与设计
例如图10.13为2-路归并排序的一个例子。
初始关键字[49][38][65][97][76][13][27]
一趟归并之后[3849][6597][1376][27]
二趟归并之后[38496597][132776]
三趟归并之后[13273849657697]
图10.132-路归并排序示例
2-路归并排序中的核心操作是将一维数组中前后相邻的两个有序序列归并为一个有序序列。
2.2.3算法描述
2.2.4程序设计与实现
2.2.5测试数据及测试结果
2.2.6算法复杂度分析
2.3快速排序(QuickSort)
2.2.1问题描述
快速排序(QuickSort)是对起泡排序的一种改进。
它的基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
2.2.2算法分析与设计
假设待排序的序列为{L.r[s],L.r[s+1],…,L.r[t]},首先任意选取一个记录(通常可选第一个记录L.r[s]作为枢轴(或支点)(pivot),然后按下述原则重新排列其余记录:
将所有关键字较它小的记录都安置在它的位置之前,将所有关键字较它大的记录都安置在它的位置之后。
这个过程称作一趟快速排序(或一次划分)。
一趟快速排序的具体做法是:
附设两个指针low和high,它们的初值分别为low和high,设枢轴记录的关键字为pivotkey,则首先从high所指位置起向前搜索找到第一个关键字小于pivotkey的记录和枢轴记录互相交换,然后从low所指位置起向后搜索,找到第一个关键字大于pivotkey的记录和枢轴记录互相交换,重复这两步直至low=high为止。
2.2.3算法描述
2.2.4程序设计与实现
2.2.5测试数据及测试结果
2.2.6算法复杂度分析
2.4众数问题
2.4.1问题描述
2.4.2算法分析与设计
2.4.3算法描述
2.4.4程序设计与实现
2.4.5测试数据及测试结果
2.4.6算法复杂度分析
2.5*马的Hamilton周游路线问题
2.5.1问题描述
2.5.2算法分析与设计
2.5.3算法描述
2.5.4程序设计与实现
2.5.5测试数据及测试结果
2.5.6算法复杂度分析
实验3动态规划
一、实验环境
操作系统:
WindowsXP编程语言:
VisualC++6.0或VS2012
二、实验目的
1、学习和了解动态规划算法的概念和基本思想;
2、熟悉对动态规划问题的分析方法及其适用范围;
3、掌握动态规划算法的设计思路和基本步骤;
4、学会使用动态规划法解决实际问题。
三、实验内容
1.旅行家问题(TSP)
2.多段图的最短路径问题
3.0-1背包问题(knapsackproblem)。
4.最长公共子序列(LCS)问题
5.数塔问题
四、实验开始
3.1旅行家问题(TSP)
3.1.1问题描述
旅行家要旅行n个城市,要求各个城市经历且仅经历一次然后回到出发城市,并要求所走的路程最短。
3.1.2算法分析与设计
各个城市间的距离可以用代价矩阵来表示。
证明TSP问题满足最优性原理
设s,s1,s2,…,sp,s是从s出发的一条路径长度最短的简单回路,假设从s到下一个城市s1已经求出,则问题转化为求从s1到s的最短路径,显然s1,s2,…,sp,s一定构成一条从s1到s的最短路径。
如若不然,设s1,r1,r2,…,rq,s是一条从s1到s的最短路径且经过n-1个不同城市,则s,s1,r1,r2,…,rq,s将是一条从s出发的路径长度最短的简单回路且比s,s1,s2,…,sp,s要短,从而导致矛盾。
所以,TSP问题满足最优性原理。
假设从顶点i出发,令d(i,V')表示从顶点i出发经过V'中各个顶点一次且仅一次,最后回到出发点i的最短路径长度,开始时,V'=V-{i},于是,TSP问题的动态规划函数为:
d(i,V')=min{cik+d(k,V-{k})}(k∈V')
(1)
d(k,{})=cki(k≠i)
(2)
从城市0出发经城市1、2、3然后回到城市0的最短路径长度是:
d(0,{1,2,3})=min{c01+d(1,{2,3}),c02+d(2,{1,3}),c03+d(3,{1,2})}
这是最后一个阶段的决策,而:
d(1,{2,3})=min{c12+d(2,{3}),c13+d(3,{2})}
d(2,{1,3})=min{c21+d(1,{3}),c23+d(3,{1})}
d(3,{1,2})=min{c31+d(1,{2}),c32+d(2,{1})}
这一阶段的决策又依赖于下面的计算结果:
d(1,{2})=c12+d(2,{})d(2,{3})=c23+d(3,{})
d(3,{2})=c32+d(2,{})d(1,{3})=c13+d(3,{})
d(2,{1})=c21+d(1,{})d(3,{1})=c31+d(1,{})
而下式可以直接获得(括号中是该决策引起的状态转移):
d(1,{})=c10=5(1→0)d(2,{})=c20=6(2→0)d(3,{})=c30=3(3→0)
再向前倒推,有:
d(1,{2})=c12+d(2,{})=2+6=8(1→2)d(1,{3})=c13+d(3,{})=3+3=6(1→3)
d(2,{3})=c23+d(3,{})=2+3=5(2→3)d(2,{1})=c21+d(1,{})=4+5=9(2→1)
(3,{1})=c31+d(1,{})=7+5=12(3→1)d(3,{2})=c32+d(2,{})=5+6=11(3→2)
再向前倒退,有:
d(1,{2,3})=min{c12+d(2,{3}),c13+d(3,{2})}=min{2+5,3+11}=7(1→2)
d(2,{1,3})=min{c21+d(1,{3}),c23+d(3,{1})}=min{4+6,2+12}=10(2→1)
d(3,{1,2})=min{c31+d(1,{2}),c32+d(2,{1})}=min{7+8,5+9}=14(3→2)
最后有:
d(0,{1,2,3})=min{c01+d(1,{2,3}),c02+d(2,{1,3}),c03+d(3,{1,2})}
=min{3+7,6+10,7+14}=10(0→1)
所以,从顶点0出发的TSP问题的最短路径长度为10,最短路径是0→1→2→3→0。
动态规划法求解TSP问题的填表过程
假设n个顶点用0~n-1的数字编号,首先生成1~n-1个元素的子集存放在数组V[2n-1]中,设数组d[n][2n-1]存放迭代结果,其中d[i][j]表示从顶点i经过子集V[j]中的顶点一次且仅一次,最后回到出发点0的最短路径长度。
填表方法:
自底向上,逐步求值。
利用前一步求出的值计算出后一步的值填入表中,每一步结束后选择最小值作为子问题的最优值,最后一步为原问题的最优解。
j
i
{}
{1}
{2}
{3}
{1,2}
{1,3}
{2,3}
{1,2,3}
0
10
1
5
8
6
7
2
6
9
5
10
3
3
12
11
14
第1步
第2步
第3步
第4步
第1步:
填写第1列,
d(1,{})=c10=5(1→0);d(2,{})=c20=6(2→0);d(3,{})=c30=3(3→0)
第2步:
d(1,{2})=c12+d(2,{})=2+6=8(1→2)d(1,{3})=c13+d(3,{})=3+3=6(1→3)
d(2,{1})=c21+d(1,{})=4+5=9(2→1)d(2,{3})=c23+d(3,{})=2+3=5(2→3)
d(3,{1})=c31+d(1,{})=7+5=12(3→1)d(3,{2})=c32+d(2,{})=5+6=11(3→2)
第3步:
d(1,{2,3})=min{c12+d(2,{3}),c13+d(3,{2})}=min{2+5,3+11}=7(1→2)
d(2,{1,3})=min{c21+d(1,{3}),c23+d(3,{1})}=min{4+6,2+12}=10(2→1)
d(3,{1,2})=min{c31+d(1,{2}),c32+d(2,{1})}=min{7+8,5+9}=14(3→2)
第4步:
d(0,{1,2,3})=min{c01+d(1,{2,3}),c02+d(2,{1,3}),c03+d(3,{1,2})}
=min{3+7,6+10,7+14}=10(0→1)
最优解为:
0→1、1→2、2→3、3→0,
即,最短路径为:
0→1→2→3→0,最短路径长度为:
10
设顶点之间的代价存放在数组c[n][n]中,动态规划法求解TSP问题的算法如下:
3.3.3算法描述
算法3.1——TSP问题
1.for(i=1;id[i][0]=c[i][0];
2.for(j=1;j<2n-1-1;j++)
for(i=1;iif(子集V[j]中不包含i)
对V[j]中的每个元素k,计算d[i][j]=min(c[i][k]+d[k][j-1]);
3.对V[2n-1-1]中的每一个元素k,计算d[0][2n-1-1]=min(c[0][k]+d[k][2n-1-2]);
4.输出最短路径长度d[0][2n-1-1];
3.1.4程序实现
3.1.5测试数据及测试结果
3.1.6算法复杂度分析
显然,算法3.1的时间复杂性为O(2n)。
和蛮力法相比,动态规划法求解TSP问题,把原来的时间复杂性是O(n!
)的排列问题,转化为组合问题,从而降低了算法的时间复杂性,但它仍需要指数时间。
3.2多段图的最短路径问题
3.2.1问题描述
设图G=(V,E)是一个带权有向连通图,如果把顶点集合V划分成k个互不相交的子集Vi(2≤k≤n,1≤i≤k),使得E中的任何一条边(u,v),必有u∈Vi,v∈Vi+m(1≤i<k,1<i+m≤k),则称图G为多段图,称s∈V1为源点,t∈Vk为终点。
多段图的最短路径问题是求从源点到终点的最小代价路径。
举例:
3.2.2算法分析与设计
3.2.3算法描述
3.2.4程序实现
3.2.5测试数据及测试结果
3.2.6算法复杂度分析
3.30-1背包问题(knapsackproblem)
3.3.1问题描述
0-1背包问题(knapsackproblem),某商店有n个物品,第i个物品价值为vi,重量(或称权值)为wi,其中vi和wi为非负数,背包的容量为W,W为一非负数。
目标是如何选择装入背包的物品,使装入背包的物品总价值最大,所选商品的一个可行解即所选商品的序列如何?
3.3.2算法分析与设计
可将这个问题形式描述如下:
约束条件为:
举例:
若商店一共有5类商品,重量分别为:
34789
价值分别为:
45101113
背包容量为:
17
则:
所选商品的一个序列为:
00011
所选商品的最大价值为24
3.3.3算法描述
3.3.4程序设计与实现
#include
#include
#include
intmin(intw,intc)
{//求2个数中的最小值
return(ww:
c);
}
intmax(intw,intc)
{//求2个数中的最大值
return(w>c?
w:
c);
}
voidknapsack(intv[],intw[],intc,intn,int**m)//求最优值
{//
intjmax=min(w[n]-1,c);
for(intj=0;j<=jmax;j++)m[n][j]=0;
for(intjj=w[n];jj<=c;jj++)m[n][jj]=v[n];
for(inti=n-1;i>1;i--)
{//递归部分
jmax=min(w[i]-1,c);
for(intj=0;j<=jmax;j++)m[i][j]=m[i+1][j];
for(intjj=w[i];jj<=c;jj++)m[i][jj]=max(m[i+1][jj],m[i+1][jj-w[i]]+v[i]);
}
m[1][c]=m[2][c];
if(c>=w[1])m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]);
cout<<"最优值:
"<cout<<"*******************************************"<}
inttraceback(int**m,intw[],intc,intn,intx[])//回代,求最优解
{//
cout<<"得到的一组最优解如下:
"<for(inti=1;iif(m[i][c]==m[i+1][c])x[i]=0;
else{x[i]=1;c-=w[i];}
x[n]=(m[n][c])?
1:
0;
for(inty=1;y<=n;y++)cout<cout<returnx[n];
}
voidmain()
{intn,c;int**m;
cout<<"请输入物品个数和重量上限:
";cin>>n>>c;
int*v=newint[n+1];
cout<<"请输入价值(v[i]):
"<for(inti=1;i<=n;i++)cin>>v[i];
int*w=newint[n+1];
cout<<"请输入重量(w[i]):
"<for(intj=1;j<=n;j++)cin>>w[j];
int*x=newint[n+1];
m=newint*[n+1];//动态分配二维数组
for(intp=0;pknapsack(v,w,c,n,m);
traceback(m,w,c,n,x);
}
3.3.5测试数据及测试结果
第1组测试数据及测试结果:
请输入物品个数和重量上限:
325
请输入价值(v[i]):
152026
请输入重量(w[i]):
101216
最优值:
35
*******************************************
得到的一组最优解如下:
110
第2组测试数据及测试结果:
请输入物品个数和重量上限:
517
请输入价值(v[i]):
34789
请输入重量(w[i]):
45101113
最优值:
12
*******************************************
得到的一组最优解如下:
01010
3.3.6算法复杂度分析
①时间复杂度分析
②空间复杂度分析
3.4最长公共子序列(LCS)问题
3.4.1问题描述
对给定序列X=(x1,x2,…,xm)和序列Z=(z1,z2,…,zk),Z是X的子序列当且仅当存在一个严格递增下标序列(i1,i2,…,ik),使得对于所有j=1,2,…,k,有zj=xij(1≤ij≤m)。
给定两个序列X和Y,当另一个序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
最长公共子序列问题就是在序列X和Y的公共子序列中查找长度最长的公共子序列。
给定两个序列:
X={x1,x2,...,xm},Y={y1,y2,...,yn},求X和Y的一个最长公共子序列。
举例:
X={a,b,c,b,d,a,b}
Y={b,d,c,a,b,a}
编写一个程序求一个最长公共子序列,求得结果应为:
最长公共子序列为:
LSC={b,c,b,a}
3.4.2算法分析与设计
3.4.3算法描述
3.4.4程序实现
3.35测试数据及测试结果
3.36算法复杂度分