算法分析与设计答案
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
用递归的方法找到 n 个不同元素的所有排列方式
//Function: 用递归的方法找到 n 个不同元素的所有排列方式 //递归原理:
//令 E= {e1 , ..., en }表示 n 个元素的集合,我们的目标是生成该集合的所有排列方式。 //令 Ei 为 E 中移去元素 i 以后所获得的集合,perm (X) 表示集合 X 中元素的排列方式,ei.perm //(X)表示在 perm(X) 中的每个排列方式的前面均加上 ei 以后所得到的排列方式。对于递归的基本部分, 采用 n = 1。 //当只有一个元素时,只可能产生一种排列方式,所以
scanf("%d", &a[i]); m=Max(a, 0, 9); printf("%d\n", m);
}
/*********************************************************************************
*分治算法求数组中最大元素算法,注意:若数组有 n 个元素,high=n-1,*
补充习题:1-4
设计算法求数组中相差最小的两个元素(称为最接近数)的差。要求给出伪代码描述, 并用一组例子进行跟踪验证,写出验证过程。 (1)伪代码 1. 令最小距离 min 等于数组头两个元素 R[0]和 R[1]的差的绝对值; 2. 从 i=0 循环至 i<n-1,对于每个 R[i] 2.1 分别求其与 j=i+1 至 j<n 的数的差的绝对值; 2.2 如果此值小于最小距离,则令新的最小距离为此值; 3. 输出最小距离。 (2)用实例进行跟踪验证
if(low==high)
return low;
else
{
mid=(low+high)/2;
max1=Max(a, low, mid);
max2=Max(a, mid+1, high);
max=a[max1]>a[max2]?max1: max2;
return max;
}
}
4.3 在 n 个元素的一个全排列
for (i=1; i <=711/4 ; i++) { for (j=i; j <=711/3 ; j++) { for (k=j; k <=711/2 ; k++) { m=711-i-j-k; if (i*j*k*m==711*1000000) { cout<<i<<endl<<j<<endl<<k<<endl<<m<<endl;
//perm (E) = ( e) , 其 中 e 是 E 中 的 唯 一 元 素 。 当 n > 1 时 , perm (E) = e1.perm (E1 ) +e2.perm(E2)+e3.perm(E3)+ ...
//+en .perm (En )。这种递归定义形式是采用 n 个 perm(X)来定义 perm (E), 其每个 X 包含 n- 1 个元素。 至此,
f(3) = f(2) + 2*3 – 1; f(2) = f(1) + 2*2 – 1; f(1) = 1;
回溯: f(2) = 1 + 3 = 4; f(3) = 4 + 5 = 9; 3)建立该算法的递推关系式,并求解。 f(n) = f(n-1) + 2n-1;
= f(n-2) + 2(n-1)-1 + 2n-1 = f(n-3) + 2(n-2)-1 + 2(n-1)-1 + 2n-1 = f(1) + 3 + 5 + 7 + ……+2n-1 = 1 + 3 + 5 +7 + …..+2n-1 = (1+2n-1)n/2 = n2 4) 将该算法转换为非递归算法。 int Q1(int n) { return n*n; }
第一章
6、考虑下面算法,回答问题 int Stery(int n) {
int S = 0; for (i = 1; i <= n; i++) {
S = S + i*i; } return S; }
1) 该算法求的是什么?
从 1 到 N 的平方和
2) 该算法基本语句是什么?S = S + i*i
3) 基本语句执行了多少次? N次
} } } } return 0; } 输出结果为:价格分别是 1.2 1.25 1.5 3.16
第四章
4.1 分治算法求数组中最大元素位置的算法:
#include <iostream> int Max(int a[], int low, int high);
void main() {
int a[10], m; for(int i=0;i<10;i++)
(参考P15)假定n = 2k 上式 = 2 = 2(2(T(n/32)+n/3)+n) = 2(2(2(T(n/33)+n/32)+n/3)+n) = 2KT(1) + 2k-1(n/3k-1) + 2k-2(n/3k-2) + …….+ 21(n/31) + n = 2k + n = n + 3n(1-) = n + 3n(1-)
由此可知,用 BF 算法一共要进行 3+1+4+1+1+6+1+1+1+6=25 次比较方能匹配出。 KMP 算法:next[]={,0,1,1,1,1,2};
由此可知,用 KMP 算法一共要进行 3+4+6+5=18 次比较方能匹配出。
3-8 对于一个平面上 n 个点的集合 S,设计蛮力算法求集合 S 的凸包的一个极点。 点集合中最左边或者最右边的点一定是凸包的一个极点,则求凸包的极点的问题转化为求 点的 x 坐标最大或最小的点 int getPole(int x[],int y[],int n) {
1.求平凡下界
第二章
2.n(logn),分治法 3.画出 a,b,c 中秋中值问题的决策树(p27)
4. 时间复杂度是 O(n),可以从 n 到 1,也可以从 1 到 n,从 n 开始就看(k/2)下取整下标的元素(也就是堆中的双亲)是否满
足大根或者小根的条件,从 1 开始就看 2k 和 2k+1 下标的元素(就是堆中的左右孩子)是否满足堆的条件
//小根堆 bool isHeap(int data, int n) {
int i, j, k; for(i = 0, j = 1;j < n;i++, j = 2*i+1) {
k = data[j]; if(j+1 < n && data[j+1] < data[j]) k = data[j+1];
if(data[i] > k) return false; } return true; }
Байду номын сангаас
第三章
3-3 对于 KMP 算法中求 next 数组问题,设计一个蛮力算法,并分析其时间性能。 整体思路: 1、next[1]、next[2]确定的,故不需要求解。 2、从 next[n]开始计算,依次计算 next[n-1]、next[n-2]、...next[3]。 3、在计算 next[j]的数值时以最大前后缀进行匹配。
voidGetNext(char T[ ], int next[ ]) {
next[1]=0; next[2]=1; j=T[0],k=0; for(; j>2; j--) {
for(n=j-2; n>=1; n--) //n 为要比较的前缀的最后一个字符的下标 {
m=j-n;//m 为要比较的后缀的第一个字符的下标 for(i=1; i<=n; i++) {
*否则运行结果不正确,谨记数组下标从 0 开
始。
*
*********************************************************************************/
int Max(int a[], int low, int high)
{
int mid, max, max1, max2;
if(T[i]!=T[m+i-1])break; } if(i==n+1) {
next[j]=n+1; break; } } if(n==0) next[j]=1; } } 3-4 假设在文本“ababcabccabccacbab”中查找模式 “abccac”,求分别采用 BF 算法和 KMP 算法进行串匹配过程中的字符比较次数。
//复杂度 O(n) //大根堆 bool isHeap(int data, int n) {
int i, j, k; for(i = 0, j = 1;j < n;i++, j = 2*i+1) {
k = data[j]; if(j+1 < n && data[j+1] > data[j]) k = data[j+1]; if(data[i] < k) return false; } return true; }
R[6]={10,5,11,16,30,14},n=6;
Min=|10-5|=5;
i=0,j=1, |R[i]-R[j]|=|10-5|=5;
j=2,|R[i]-R[j]|=|10-11|=1<min;min=1;
j=3, |R[i]-R[j]|=|10-16|=6;
j=4, |R[i]-R[j]|=|10-30|=20; j=5, |R[i]-R[j]|=|10-14|=4; i=1,j=2, |R[i]-R[j]|=|5-11|=6; j=3, |R[i]-R[j]|=|5-16|=11; j=4, |R[i]-R[j]|=|5-30|=15; j=5, |R[i]-R[j]|=|5-14|=9; i=2,j=3, |R[i]-R[j]|=|11-16|=5; j=4, |R[i]-R[j]|=|11-30|=19; j=5, |R[i]-R[j]|=|11-14|=3; i=3,j=4, |R[i]-R[j]|=|16-30|=14; j=5, |R[i]-R[j]|=|16-14|=2; i=4,j=5, |R[i]-R[j]|=|30-14|=16; 最后输出 min=1
4) 该算法的效率类型是什么? O(n)
5) 对该算法进行改进,分析改进的算法效率。 利用公式法进行求解 int Stery1(int n) {
return (n(n+1)(2n+1))/6; } O(1)
6) 如果算法不能在改进了,请证明这一点。 因为其时间复杂度已经是常数级,不能再小了。
7、使用扩展递推技术求解下列递推关系式
当然也可以使用通用分支递推式,可快速确定答案。
8、考虑下面的递归算法,回答下面问题 int Q(int n) //n 为正整数
{ if(n == 1) return 1; else return Q(n-1)+2*n-1;
}
1) 该算法求的是什么? 求一个正整数的平方 2) 写出n=3时的执行过程;
2、 使用 k 层嵌套循环生成元素个数为 k 个的组合。
设 k=3;n 个元素存储在数组 a[]中; 伪代码:
for (i=1; i<n-2; i++) for(j=i+1; i<n-1; i++) for(k=j+1; i<n; i++)
输出 a[i]a[j]a[k]构成的组合。
3-13 美国有个连锁店叫 7-11 这个连锁店以前是每天 7 点开门,晚上 11 点关门 不过现在是全天 24 小时营业。有一天,有个人来到这个连锁店,买了 4 件商品 营业员拿起计算器敲了一下,说:总共是$7.11 顾客开玩笑说:所以你们商店就叫 7-11?营 业员没有理她,说:当然不是,我是把它们的价格相乘之后得到的。 顾客说:相乘?你应该把他相加才对。营业员说,我弄错了。接着又算了一遍,结果让两个 人吃惊的是:计算结果也是$7.11 请问,这 4 件商品的价格是多少? 参考代码: #include<iostream.h> #include <stdio.h> int main() { long i,j,k,m;
int r=0; for(inti=0;i<n;i++) {
if(x[i]>x[r])r=i; } return r; } 3-11 设计算法生成在 n 个元素中包含 k 个元素的所有组合对象。 两种思路: 1、 生成所有的组合,在组合中找元素个数为 k 个的组合。 伪代码: 1.初始化一个长度为 n 的比特串 s=00…0 并将对应的子集输出; 2.for(i=1; i<2n; i++) //注意不能书写成 i<=2n 2.1 s++; 2.2 判断 s 中 1 的个数,若为 k,则将 s 对应的子集输出;