算法设计与分析(李春保)练习题答案v1

 

 

1.11 概论

 

1.1.1练习题

 

1.下列于算法的说法中确的有()。

 

Ⅰ.求解某一类题的算法是唯一

 

Ⅱ.算法必须在限步操作之后停

 

Ⅲ.算法的每一操作必须是明确,不能有歧义或义模糊

 

Ⅳ.算法执行后定产生确定的结

 

A. 1 B.2 C.3 D.4

 

2. T(n)表示当入规模为n时的算法效率,以下法效率最优的是)。

 

 

A.T(n)= T(n-1)+1T(1)=1 C.T(n)= T(n/2)+1T(1)=1

 

B.T(n)= 2n

 

D.T(n)=3nlog2n

 

 

3.什么算法?算法有哪特征?

 

4.判断一个2的正整数n是否为素数的方有多种,给出两算法,说明其中一种算法更好的由。

 

5.证明下关系成立:

 

110n-2n=(n)

 

22=(2)

 

6.证明O(f(n))+O(g(n))=O(max{f(n)g(n)})

 

7.个含nn>2)个数的数组a,判断中是否存在出现数超过所有元素半的元素。

 

8.一个符串采用string 象存储,设计一算法判断该字符是否为回文。

 

9.有一个整序列,设计一个算法判断其中是存在两个元素和好等于给定的整k

 

10.有两个整序列,每个整数序列中所有元素不相同。设计一算法求它们的公共元素,要求不使STL 的集合算

 

11.正整nn>1)可以写成质数的乘积式,称为整数的质因数分解。如,12=2*2*318=2*3*311=11。设计一个法求n这样分解后各个质因数现的次数,采vector 向量存结果。

 

12.有一个数序列,所有元素均不相同,设一个算法求相差小的元素对的个数。如序列4123的相差最小的元素对的数是3,其元素对是(12),(23),34)。

 

13.有一个mapint>容器,其中已经存放了多元素。设计一算法求出其中重复的value 返回重复value 数。

 

14.做第10,采用map 容器存放终结果。

 

15.假设有一nn>1)个元素的stackst,设计一个法出栈从栈顶到栈底的第k1kn)个元素,他栈元素不变。

 

 

 

 

算法设计

 

1.1.2练习题参考答

 

1.答:由于法具有有穷性、确定性和输出性因而确,而解决某一类问题的算法不定是唯一的。答C

 

2.答:A的时间复杂度为O(n)。选项B的时间复杂度为O(n)。选项C的时间复杂度为O(log2n)。选项D 的时复杂度为O(nlog2n)。答案为C

 

3.答:算法求解问题的一系列计算步骤。算具有有限性、确性、可行性、输入性和输出性5 重要特征。

 

4.答:种算法如下:

 

#include

 

#include

 

boolisPrime1(intn)//1

 

{for (int i=2;i

 

if (n%i==0)

 

return false;

 

return true;

 

}

 

boolisPrime2(intn)//2

 

{for (int i=2;i<=(int)sqrt(n);i++)

 

if (n%i==0)

 

return false;

 

return true;

 

}

 

voidmain()

 

{int n=5;

 

printf("%d,%d\n",isPrime1(n),isPrime2(n));

 

}

 

方法1 的时间复度为O(n),方法2的时间复杂度n,所以2 更好。5.答:1)当n 足够大(10n-2n)/( n)=10所以10n-2n=(n)

 

22=2*2=(2)

 

6.明:对于任意f1(n)O(f(n)),存在正c1 和正常数n1使得对所有nn1f1(n)c1f(n)

 

类似地,对于任g1(n)O(g(n)),存在正常数c2 自然数n2,使得所有nn2g1(n)c2g(n)

 

c3=max{c1c2}n3=max{n1n2}h(n)= max{f(n)g(n)}

 

则对所有的nn3,有:

 

f1(n) +g1(n)c1f(n) +c2g(n)c3f(n)+c3g(n)=c3(f(n)+g(n))

 

c32max{f(n)g(n)}=2c3h(n)=O(max{f(n)g(n)})

 

7.先将a 中元素递排序,再求出现数最多的次数maxnum,最后判断否满足条件。对应的序如下:

 

#include

 

#include

 

using namespace std;

 

2

 

 

 

 

1

 

概论

 

 

boolsolve(inta[],intn,int&x)

 

 

{sort(a,a+n);

 

int maxnum=0;

 

int num=1;

 

int e=a[0];

 

for (int i=1;i

 

{if (a[i]==e)

 

{num++;

 

//递增排序

 

//出现次数最多的

 

 

if (num>maxnum)

 

{maxnum=num;

 

x=e;

 

}

 

}

 

else

 

{e=a[i];

 

num=1;

 

}

 

}

 

if (maxnum>n/2)

 

return true;

 

else

 

return false;

 

}

 

voidmain()

 

{int a[]={2,2,2,4,5,6,2};

 

int n=sizeof(a)/sizeof(a[0]);

 

int x;

 

if (solve(a,n,x))

 

printf("出现次数过所有元素一半的元素为%d\n",x); else

 

printf("不存在出次数超过所有元素一半的元素\n");

 

}

 

上述程序的执行果如图1.1 所示

 

 

1.1

 

程序执行结果

 

 

8.解:用前后字符判断法,对应的程序下:#include

 

#include

 

using namespace std;

 

boolsolve(stringstr)//断字符串str为回文{int i=0,j=str.length()-1;

 

while (i

 

{if (str[i]!=str[j])

 

return false;

 

3

 

 

 

 

算法设计

 

i++; j--;

 

}

 

return true;

 

}

 

voidmain()

 

{cout << "结果"<<endl;

 

string str="abcd";

 

cout << "" << str<<(solve(str)?"是回":"不是回文")<< endl; string str1="abba";

 

cout << "" << str1<<(solve(str1)?"是回文":"回文")<<endl;}

 

上述程序的执行果如图1.2所示

 

 

1.2

 

程序执行结果

 

 

9.解:a 中元素递增序,然后从两端始进行判断。对的程序如下:#include

 

#include

 

using namespace std;

 

boolsolve(inta[],intn,intk)

 

 

{sort(a,a+n);

 

int i=0, j=n-1;

 

while (i

 

{if (a[i]+a[j]==k)

 

return true;

 

//递增排序

 

//区间中存在两个者以上元素

 

 

else if (a[i]+a[j]

 

i++;

 

else

 

j--;

 

}

 

return false;

 

}

 

voidmain()

 

{int a[]={1,2,4,5,3};

 

int n=sizeof(a)/sizeof(a[0]);

 

printf("求解结果\n");

 

int k=9,i,j;

 

if (solve(a,n,k,i,j))

 

printf("存在: %d+%d=%d\n",a[i],a[j],k);else

 

printf("不存在个元素和为%d\n",k);

 

int k1=10;

 

if (solve(a,n,k1,i,j))

 

printf("存在: %d+%d=%d\n",a[i],a[j],k1);

 

4

 

 

 

 

1

 

概论

 

 

else

 

 

printf("

 

不存在两个元素和%d\n",k1);

 

 

}

 

上述程序的执行果如图1.3 所示

 

 

1.3

 

程序执行结果

 

 

10.解:采用集合set储整数序列,集中元素默认是递增排序的,再用二路归并算法求它的交集。对应的序如下:

 

#include

 

#include

 

using namespace std;

 

 

voidsolve(sets1,sets2,set&s3){set::iteratorit1,it2;

 

it1=s1.begin(); it2=s2.begin();

 

while (it1!=s1.end()&& it2!=s2.end())

 

{if (*it1==*it2)

 

{s3.insert(*it1);

 

++it1; ++it2;

 

}

 

else if (*it1<*it2)

 

++it1;

 

else

 

++it2;

 

}

 

}

 

//s3

 

 

voiddispset(sets)

 

{set::iteratorit;

 

//集合的元素

 

 

for (it=s.begin();it!=s.end();++it)

 

printf("%d ",*it);

 

printf("\n");

 

}

 

voidmain()

 

{int a[]={3,2,4,8};

 

int n=sizeof(a)/sizeof(a[0]);

 

set s1(a,a+n);

 

int b[]={1,2,4,5,3};

 

int m=sizeof(b)/sizeof(b[0]);

 

set s2(b,b+m);

 

set s3;

 

solve(s1,s2,s3);

 

printf("求解结果\n");

 

printf("s1: ");dispset(s1);

 

 

5

 

 

 

 

算法设计

 

 

printf("

 

printf("

 

s2: "); dispset(s2);

 

s3: "); dispset(s3);

 

 

}

 

上述程序的执行果如图1.4 所示

 

 

1.4

 

程序执行结果

 

 

11.解:正整数n,从i=2 始查找其质因数ic 记录质因数i 的次数,当找到这样质因数后将(iic)作为一个素插入到vector v 中。最后输出v对应的算法如下:

 

#include

 

#include

 

using namespace std;

 

 

struct NodeType

 

{int p;

 

int pc;

 

//vector向量元素 //质因数

 

//质因数出现次数

 

 

};

 

voidsolve(intn,vector&v)//n{int i=2;

 

int ic=0;

 

NodeType e;

 

do

 

{if (n%i==0)

 

{ic++;

 

n=n/i;

 

}

 

else

 

{if (ic>0)

 

{e.p=i;

 

e.pc=ic;

 

v.push_back(e);

 

}

 

ic=0;

 

i++;

 

}

 

} while (n>1 || ic!=0);

 

}

 

voiddisp(vector&v)//v

 

{vector::iteratorit;

 

for (it=v.begin();it!=v.end();++it)

 

printf("质因数%d出现%d\n",it->p,it->pc);

 

}

 

6

 

 

 

 

1

 

概论

 

 

voidmain()

 

{vectorv;

 

int n=100;

 

printf("n=%d\n",n);

 

solve(n,v);

 

disp(v);

 

}

 

上述程序的执行果如图1.5 所示

 

 

1.5

 

程序执行结果

 

 

12.解:增排序,再求相邻元素差,比较最小元素差,累最小元素差的个数。对应的程序下:

 

#include

 

#include

 

#include

 

using namespace std;

 

 

intsolve(vector&myv)

 

//myv中相最小的元素对的个数

 

 

{sort(myv.begin(),myv.end());//递增排序

 

int ans=1;

 

int mindif=myv[1]-myv[0];

 

for (int i=2;i

 

{if (myv[i]-myv[i-1]

 

{ans=1;

 

mindif=myv[i]-myv[i-1];

 

}

 

else if (myv[i]-myv[i-1]==mindif)

 

ans++;

 

}

 

return ans;

 

}

 

voidmain()

 

{int a[]={4,1,2,3};

 

int n=sizeof(a)/sizeof(a[0]);

 

vector myv(a,a+n);

 

cout << "相差最的元素对的个数:" << solve(myv) <<endl; }

 

上述程序的执行果如图1.6

 

 

7

 

 

 

 

 

1.6


算法设计

 

程序执行结果

 

 

13.解:对于mapint>容器mymap,设计另外一mapint>容器tmap将前者的value 后者的关键字。mymap,累计tmap 中相同关键字次数。一个参考程序及其输结果如下

 

#include

 

#include

 

#include

 

using namespace std;

 

voidmain()

 

{mapmymap;

 

mymap.insert(pair("Mary",80));

 

mymap.insert(pair("Smith",82));

 

mymap.insert(pair("John",80));

 

mymap.insert(pair("Lippman",95));

 

mymap.insert(pair("Detial",82));

 

map::iteratorit;

 

map tmap;

 

for (it=mymap.begin();it!=mymap.end();it++)

 

tmap[(*it).second]++;

 

mapint>::iteratorit1;

 

cout << "求解结"<<endl;

 

for (it1=tmap.begin();it1!=tmap.end();it1++)

 

cout << "" << (*it1).first<< ":" << (*it1).second<< "\n";

 

}

 

上述程序的执行果如图1.7 所示

 

 

1.7

 

程序执行结果

 

 

14.解:采用mapint>容器mymap 存放解结果,第一个量存放质因数,二个分量存放质数出现次数。对的程序如下:

 

#include

 

#include

 

using namespace std;

 

voidsolve(intn,map&mymap)//n分解

 

{int i=2;

 

int ic=0;

 

do

 

 

{

 

if (n%i==0)

 

{ic++;

 

n=n/i;

 

}

 

 

8

 

 

 

 

1

 

概论

 

 

else

 

{if (ic>0)

 

mymap[i]=ic;

 

ic=0;

 

i++;

 

}

 

} while (n>1 || ic!=0);

 

}

 

voiddisp(map&mymap)//mymap

 

{map::iteratorit;

 

for (it=mymap.begin();it!=mymap.end();++it)

 

printf("质因数%d出现%d\n",it->first,it->second);

 

}

 

voidmain()

 

{mapmymap;

 

int n=12345;

 

printf("n=%d\n",n);

 

solve(n,mymap);

 

disp(mymap);

 

}

 

上述程序的执行果如图1.8

 

 

1.8

 

程序执行结果

 

 

15.解:栈容不能顺序遍历,为此创建一个临tmpst 栈,将st k个元素出栈并进栈到tmpst 再出栈tmpst一次得到第k 个元素最后将栈tmpst 有元素出栈并进栈到st 中。对应程序如下:

 

#include

 

#include

 

using namespace std;

 

 

intsolve(stack&st,intk)

 

{stack tmpst;

 

int e;

 

for (int i=0;i

 

{e=st.top();

 

st.pop();

 

tmpst.push(e);

 

}

 

e=tmpst.top();

 

tmpst.pop();

 

while (!tmpst.empty())

 

{st.push(tmpst.top());

 

tmpst.pop();

 

//k个元

 

//出栈stk素并进tmpst//求第k个元素

 

//tmpst的所有素出栈并进栈st9

 

 

 

 

 

}

 

return e;

 

}

 

voiddisp(stack&st)

 

{while (!st.empty())

 

{printf("%d ",st.top());

 

st.pop();

 

}

 

printf("\n");

 

}

 

voidmain()

 

{stack st;


算法设计

 

//st

 

 

printf("进栈元素1,2,3,4\n");st.push(1);

 

st.push(2);

 

st.push(3);

 

st.push(4);

 

int k=3;

 

int e=solve(st,k);

 

printf("出栈第%d元素是: %d\n",k,e);printf("st中元素栈顺序: "); disp(st);

 

}

 

上述程序的执行果如图1.9 所示

 

 

1.9

 

程序执行结果

 

 

1.22 递归算法设计技术

 

1.2.1练习题

 

1.什么直接递归和间接归?消除递归一要用到什么数据构?2.分析下程序的执行结

 

#include

 

voidf(intn,int&m)

 

{if (n<1) return;

 

else

 

 

{

 

}

 

printf("调用f(%d,%d),n=%d,m=%d\n",n-1,m-1,n,m);n--; m--;

 

f(n-1,m);

 

printf("调用f(%d,%d):n=%d,m=%d\n",n-1,m-1,n,m);

 

10

 

 

 

 

1

 

概论

 

 

}

 

voidmain()

 

{int n=4,m=4;

 

f(n,m);

 

}

 

3.采用接推导方法求解下递归方程:T(1)=1

 

T(n)=T(n-1)+nn>1

 

4.采用征方程方法求解下递归方程:H(0)=0

 

H(1)=1

 

H(2)=2

 

H(n)=H(n-1)+9H(n-2)-9H(n-3)n>2 5.采用归树方法求解以递归方程:T(1)=1

 

T(n)=4T(n/2)+nn>1

 

6.采用方法求解以下题递归方程。

 

 

T(n)=1

 

n=1

 

 

T(n)=4T(n/2)+nn>1

 

7.分析斐波那契f(n)间复杂度。

 

8.的首项a1=0,后奇数项和偶数项计算公式分别为a2n=a2n-1+2a2n+1=a2n- 1+a2n-1,写出计数列第n项的递归算法。

 

9.于一个采用字符数组存放的字str,设计一个递归算法求其符个数(长)。

 

10.于一个采用字符组存放的字符串str,设计一个归算法判断str 否为回文。

 

11.不带头结点的单链表L,设计一递归算法正序输所有结点值。

 

12.不带头结点的单链表L,设计一递归算法逆序输所有结点值。

 

13.对于不头结点的非空单L,设计一个递归算法返回最值结点的地址(设这样的结点唯)。

 

14.对于不头结点的单链表L,设计一个递归算法返回第一个x 的结点的地址,没有这样的点时返回NULL

 

15.不带头结点的单链表L,设计一递归算法删除第个值为x 的结点

 

16.假设叉树采用二叉链储结构存放,结点值为int 类型设计一个递归算法求二叉树bt 中所有子结点值之和。

 

17.假设叉树采用二叉链储结构存放,结点值为int 类型设计一个递归算法求二叉树bt 中所有点值大于等于k 结点个数。

 

18.假设二叉采用二叉链存储结构存放,所有点值均不相同,计一个递归算法求值为x 的结点层次(根结点的次为1),没有找到样的结点时返回0

 

11

 

 

 

 

算法设计

 

1.2.2练习题参考答

 

1.答:一个f 数定义中直接调用f 函数自己,为直接递归。一f 函数定义中调g 函数,而g 数的定义中调用f 数,称为间接递。消除递归一般用栈实现。

 

2.答:归函数f(nm)n是非引用参数m是引用参数,所以递归函数的态为n)。程序执结果如下:

 

调用f(3,3),n=4,m=4

 

调用f(1,2),n=2,m=3

 

调用f(0,1),n=1,m=2

 

调用f(2,1),n=3,m=2

 

3.解:T(n)的过程如

 

T(n)=T(n-1)+n=[T(n-2)+n-1)]+n=T(n-2)+n+(n-1)

 

=T(n-3)+n+(n-1)+(n-2)

 

=

 

=T(1)+n+(n-1)++2

 

=n+(n-1)+ ++2+1=n(n+1)/2=O(n)

 

 

4.整数一个常系的线性齐次递推,用x

 

n-33232

 

代替H(n),有x=x+9x-9x

 

 

x-x-9x+9=x(x-9)-(x-9)=(x-1)(x-9)=(x-1)(x+3)(x-3)=0得到r1=1r2=-3r3=3则递归方程的通为:H(n)=c1+c2(-3)+c33

 

代入H(0)=0c1+c2+c3=0

 

代入H(1)=1c1-3c2+3c3=1

 

 

代入H(2)=2c1+9c2+9c3=2

 

求出:c1=-1/4c2=-1/12c3=1/3H(n)=c1+c2(-3)+c33=(

 

n1

 

4

 

+ 13

 

1

 

 

5.解:构造递归树如图1.10 所示,第1 问题规模为n,第2 的层的子问问题规模为n/2此类推,当展开k+1层,其规模为n/2=1,所以递归的高度为log2n+1

 

1层有1个结点其时间为n,第24个结点,其间为4(n/2)=2n,依次类推,第k 层有4点,每个子问题规模为n/2其时间为4(n/2)=2n。叶子结点个数为n 个,其时间为n将递归树每一层时间加起来,可

 

logn

T(n)=n+2n++ 2n++n2=O(n)

 

 

12

 

 

 

 

1

 

概论

 

 

n

 

n

 

 

(n/2)

 

(n/2)

 

(n/2)

 

(n/2)

 

2n

 

 

高度h log2n+1

 

(n/2)

 

 

1

 

(n/2)

 

 

1

 

(n/2)

 

 

1

 

(n/2)

 

 

1

 

2n

 

n

 

 

1.10一棵递归

 

6.解:用主方法求解,a=4b=2f(n)=n

logalog4

因此,==n,它与f(n)大,满足主定理的情况(2),所以T(n)=O( loga

log2n)=O(nlog2n)

 

7.解:求斐波那契f(n)时间为T(n),有以下递推式:

 

T(1)=T(2)

 

 

T(n)=T(n-1)+T(n-2)+1

 

n>2

 

 

其中,T(n)式中1表示一次加法运算的时间。

 

不妨先求T1(1)=T1(2)=1T1(n)=T1(n-1)+T1(n-2),按《教程》例2.14的方法可以求

 

 

出:

 

 

T1(n)=

 

1

 

5

 

15

 

 

1

 

5

 

15

 

115=

 

 

T(n)=T1(n)+1

 

1

 

5

 

15

 

+1=O(φ),其中φ=

2

 

 

8.解:f(m)计算数列第m项值。

 

m 为偶数时不妨设m=2n2n-1=m-1,所f(m)=f(m-1)+2

 

m 为奇数时不妨设m=2n+12n-1=m-22n=m-1,所以有f(m)=f(m-2)+f(m-1)-1

 

对应的递归算法下:

 

intf(int m)

 

{if (m==1) return0;

 

if (m%2==0)

 

return f(m-1)+2;

 

else

 

return f(m-2)+f(m-1)-1;

 

}

 

9.解:f(str)返回字符串str的长度,其递归型如下:

 

 

f(str)=0

 

f(str)=f(str+1)+1

 

*str='\0'

 

其他情况

 

 

对应的递归程序下:

 

 

13

 

 

 

 

 

#include

 

using namespace std;

 

intLength(char*str)

 

{if (*str=='\0')

 

return 0;

 

else

 

return Length(str+1)+1;

 

}

 

voidmain()

 

{char str[]="abcd";


算法设计

 

//str的字个数

 

 

cout << str << "长度:"<<Length(str) << endl; }

 

上述程序的执行果如图1.11 所示

 

 

1.11

 

程序执行结果

 

 

10.f(strn)返回含n 个字符的字str是否为回文,其递归模型下:

 

 

f(strn)=true

 

f(strn)=flase

 

f(strn)=f(str+1n-2)

 

n=0 或者n=1 str[0]str[n-1]其他情况

 

 

对应的递归算法下:

 

#include

 

#include

 

boolisPal(char*str,intn)//str判断算法{if (n==0 ||n==1)

 

return true;

 

if (str[0]!=str[n-1])

 

return false;

 

return isPal(str+1,n-2);

 

}

 

voiddisp(char*str)

 

{int n=strlen(str);

 

if (isPal(str,n))

 

printf("%s是回\n",str);

 

else

 

printf("%s不是\n",str);

 

}

 

voidmain()

 

{printf("结果\n");

 

disp("abcba");

 

disp("a");

 

disp("abc");

 

}

 

14

 

 

 

 

1

 

概论

 

 

上述程序的执行果如图1.12 所示

 

 

1.12

 

程序执行结果

 

 

11.f(L)正序输出单链表L 的所有结值,其递归模型下:

 

 

f(L)不做任何事

 

f(L)输出L->data; f(L->next);对应的递归程序下:#include "LinkList.cpp"

 

L=NULL

 

LNULL

 

//包含单链表的基运算算法

 

 

voiddispLink(LinkNode*L)//序输出所有结点值{if (L==NULL)return;

 

else

 

{printf("%d ",L->data);

 

dispLink(L->next);

 

}

 

}

 

voidmain()

 

{int a[]={1,2,5,2,3,2};

 

int n=sizeof(a)/sizeof(a[0]);

 

LinkNode *L;

 

 

CreateList(L,a,n);printf("正向L: ");dispLink(L); printf("\n");

 

Release(L);

 

//a[0..n-1]不带头结点的单链表 //销毁单链表

 

 

}

 

上述程序的执行果如图1.13 所示

 

1.13

 

程序执行结果

 

 

12.f(L)逆序输出单链表L 的所有结值,其递归模型下:

 

 

f(L)不做任何事

 

f(L)f(L->next);输出L->data对应的递归程序下:

 

#include "LinkList.cpp"

 

voidRevdisp(LinkNode*L)

 

{if (L==NULL)return;

 

L=NULL

 

LNULL

 

//包含单链表的基运算算法//输出所有结点值

 

15

 

 

 

 

 

else

 

{Revdisp(L->next);

 

printf("%d ",L->data);

 

}

 

}

 

voidmain()

 

{int a[]={1,2,5,2,3,2};

 

int n=sizeof(a)/sizeof(a[0]);

 

LinkNode *L;

 

CreateList(L,a,n);

 

printf("反向L: ");

 

Revdisp(L); printf("\n");

 

Release(L);

 

}

 

上述程序的执行果如图1.14 所示

 

1.14


算法设计

 

程序执行结果

 

 

13.f(L)返回单链表L 中值最大结点地址,其递归模如下:

 

 

f(L) = L

 

f(L) =MAX{f(L->next)L->data}对应的递归程序下:#include "LinkList.cpp"

 

L 只有一个结点其他情况

 

//包含单链表的基运算算法

 

 

LinkNode*Maxnode(LinkNode*L)//{if (L->next==NULL)

 

 

return L;

 

else

 

{LinkNode *maxp;

 

maxp=Maxnode(L->next);

 

if (L->data>maxp->data)

 

return L;

 

else

 

return maxp;

 

}

 

}

 

voidmain()

 

{int a[]={1,2,5,2,3,2};

 

//只有一个结点时

 

 

int n=sizeof(a)/sizeof(a[0]);

 

LinkNode *L,*p;

 

CreateList(L,a,n);

 

p=Maxnode(L);

 

printf("最大结点:%d\n",p->data); Release(L);

 

 

16

 

 

 

 

1

 

概论

 

 

}

 

上述程序的执行果如图1.15 所示

 

1.15

 

程序执行结果

 

 

14.f(Lx)返回单链表L 中第一个值x 的结点的地址其递归模型如下

 

 

f(Lx) = NULL

 

f(Lx) = L

 

f(Lx) =f(L->nextx) 对应的递归程序下:

 

L=NULL

 

LNULL L->data=x 其他情况

 

 

#include "LinkList.cpp"

 

LinkNode*Firstxnode(LinkNode*L,intx) {if (L==NULL)return NULL;

 

if (L->data==x)

 

return L;

 

else

 

return Firstxnode(L->next,x);

 

}

 

voidmain()

 

{int a[]={1,2,5,2,3,2};

 

int n=sizeof(a)/sizeof(a[0]);

 

LinkNode *L,*p;

 

CreateList(L,a,n);

 

int x=2;

 

p=Firstxnode(L,x);

 

printf("结点值: %d\n",p->data);Release(L);

 

}

 

上述程序的执行果如图1.16 所示

 

//包含单链表的基运算算法

 

//第一个值为x的结

 

 

1.16

 

程序执行结果

 

 

15.f(Lx)删除单链表L 中第一个值x 的结点,其递模型如下:

 

 

f(Lx)不做任何

 

f(Lx)删除L L=L->nextf(Lx)f(L->nextx)

 

对应的递归程序下:

 

L=NULL

 

LNULL L->data=x 其他情况

 

17

 

 

 

 

 

#include "LinkList.cpp"


算法设计

 

//包含单链表的基运算算法

 

 

voidDelfirstx(LinkNode*&L,intx)//除单链表L中第个值为x{if (L==NULL)return;

 

if (L->data==x)

 

{LinkNode *p=L;

 

L=L->next;

 

free(p);

 

}

 

else

 

Delfirstx(L->next,x);

 

}

 

voidmain()

 

{int a[]={1,2,5,2,3,2};

 

int n=sizeof(a)/sizeof(a[0]);

 

LinkNode *L;

 

CreateList(L,a,n);

 

printf("删除前L:"); DispList(L);

 

int x=2;

 

printf("删除第一值为%d的结点\n",x);

 

Delfirstx(L,x);

 

printf("删除后L:"); DispList(L);

 

Release(L);

 

}

 

上述程序的执行果如图1.17 所示

 

 

1.17

 

程序执行结果

 

 

16.f(bt)返回二叉树bt 中所有叶子结值之和,其递归型如下:

 

 

f(bt)=0

 

f(bt)=bt->data

 

f(bt)=f(bt->lchild)+f(bt->rchild) 对应的递归程序下:#include "Btree.cpp"

 

intLeafSum(BTNode*bt)

 

{if (bt==NULL)return 0;

 

bt=NULL

 

btNULL bt 为叶子结点其他情况

 

//包含二叉树的基运算算法

 

//bt

 

 

if (bt->lchild==NULL&& bt->rchild==NULL)

 

return bt->data;

 

int lsum=LeafSum(bt->lchild);

 

int rsum=LeafSum(bt->rchild);

 

return lsum+rsum;

 

}

 

voidmain()

 

18

 

 

 

 

1

 

概论

 

 

{

 

BTNode *bt;

 

Int a[]={5,2,3,4,1,6};//序列

 

Int b[]={2,3,5,1,4,6};//序列

 

int n=sizeof(a)/sizeof(a[0]);bt=CreateBTree(a,b,n);//ab构造二叉链bt printf("二叉树bt:");DispBTree(bt);printf("\n"); printf("所有叶子点值之和:%d\n",LeafSum(bt));

 

 

DestroyBTree(bt);

 

//销毁树bt

 

 

}

 

上述程序的执行果如图1.18 所示

 

 

1.18

 

程序执行结果

 

 

17.解:f(btk)返回二叉树bt 中所有结值大于等于k 点个数,其递归模型如下:

 

 

f(btk)=0

 

f(btk)=f(bt->lchildk)+f(bt->rchildk)+1f(btk)=f(bt->lchildk)+f(bt->rchildk)

 

对应的递归程序下:

 

#include "Btree.cpp"

 

intNodenum(BTNode*bt,intk)

 

{if (bt==NULL)return 0;

 

int lnum=Nodenum(bt->lchild,k);

 

int rnum=Nodenum(bt->rchild,k);

 

if (bt->data>=k)

 

return lnum+rnum+1;

 

else

 

return lnum+rnum;

 

}

 

voidmain()

 

{BTNode *bt;

 

Int a[]={5,2,3,4,1,6};

 

Int b[]={2,3,5,1,4,6};

 

int n=sizeof(a)/sizeof(a[0]);

 

bt=CreateBTree(a,b,n);

 

bt=NULL

 

btNULL bt->datak其他情况

 

//包含二叉树的基运算算法//等于k的结个数

 

//ab构造二叉bt

 

 

printf("二叉树bt:");DispBTree(bt);printf("\n"); int k=3;

 

printf("大于等于%d的结点个数:%d\n",k,Nodenum(bt,k));

 

 

DestroyBTree(bt);

 

//销毁树bt

 

 

}

 

上述程序的执行果如图1.19 所示

 

 

19

 

 

 

 

算法设计

 

 

1.19

 

程序执行结果

 

 

18.解:f(btxh)返回二叉树btx 结点的层次其中h 表示bt 结点的层次,初始调用时bt 指向根结点,h 1。其递归模如下:

 

 

f(btxh)=0

 

f(btxh)=h

 

f(btxh) =l

 

f(btxh) =f(bt->rchildxh+1) 对应的递归程序下:

 

bt=NULL

 

btNULL bt->data=xl=f(bt->lchildxh+1)0其他情况

 

 

#include "Btree.cpp"

 

intLevel(BTNode*bt,intx,int h) {//初始调用bt为根,h1

 

if (bt==NULL) return0;

 

if (bt->data==x)

 

return h;

 

//包含二叉树的基运算算法//叉树btx

 

//找到x结点,返h

 

 

else

 

{int l=Level(bt->lchild,x,h+1);//在左子树中

 

 

if (l!=0)

 

return l;

 

else

 

//在左子树中找到返回其层次l

 

 

return Level(bt->rchild,x,h+1);//回在右子树的查找

 

 

}

 

}

 

voidmain()

 

{BTNode *bt;

 

Int a[]={5,2,3,4,1,6};

 

Int b[]={2,3,5,1,4,6};

 

int n=sizeof(a)/sizeof(a[0]);

 

bt=CreateBTree(a,b,n);

 

//ab构造二bt

 

 

printf("二叉树bt:");DispBTree(bt);printf("\n"); int x=1;

 

printf("%d结点的: %d\n",x,Level(bt,x,1));

 

 

DestroyBTree(bt);

 

}

 

上述程序的执行果如图1.20 所示

 

//销毁树bt

 

 

1.20

 

程序执行结果20

 

 

 

 

1

 

概论

 

 

1.33 分治法

 

1.3.1练习题

 

1.分治法的计思想是将一个难以直接解决的问题分割成规模小的子问题,分别解决子问题,后将子问题的解合起来形成原的解。这要求原题和子问题)。

 

A.问题规模相,问题性质相同

 

B.问题规模相同问题性质不同

 

C.问题规模不同问题性质相同

 

D.问题规模不,问题性质不同

 

2.在寻找n 个元中第k 小元素问中,如快速排序法思想,运用分算法对n个元素进行划分如何选择划分基?下面()答解释最合理。

 

A.随机选择一元素作为划分基准

 

B.取子序列的第个元素作为划分

 

C.用中位数的中数方法寻找划分

 

D.以上皆可行但不同方法,算法复杂度上界可不同

 

3.对于列二分查找算法以下正确的是()。

 

A.

 

intbinarySearch(inta[],intn,int x)

 

{int low=0, high=n-1;

 

while(low<=high)

 

{int mid=(low+high)/2;

 

if(x==a[mid]) returnmid;

 

if(x>a[mid]) low=mid;

 

else high=mid;

 

}

 

return 1;

 

}

 

B.

 

intbinarySearch(inta[],intn,int x)

 

{int low=0, high=n-1;

 

while(low+1!=high)

 

{int mid=(low+high)/2;

 

if(x>=a[mid]) low=mid;

 

else high=mid;

 

}

 

if(x==a[low]) returnlow;

 

else return 1;

 

}

 

C.

 

intbinarySearch(inta[],intn,intx)

 

{int low=0, high=n-1;

 

while(low

 

{int mid=(low+high)/2;

 

21

 

 

 

 

算法设计

 

if(x

 

high=mid;

 

else low=mid;

 

}

 

if(x==a[low]) returnlow;

 

else return 1;

 

}

 

D.

 

intbinarySearch(inta[],intn,int x)

 

{if(n > 0 &&x >= a[0])

 

{int low = 0,high = n-1;

 

while(low < high)

 

{int mid=(low+high+1)/2;

 

if(x < a[mid])

 

high=mid-1;

 

else low=mid;

 

}

 

if(x==a[low]) returnlow;

 

}

 

return 1;

 

}

 

4.快速序算法是根据分策略来设计的,述其基本思想。

 

5.假设含n 个元素的待排的数据a 恰好是减排列的,说明QuickSort(a0n-1)递增排时间复杂度为O(n)

 

6.以下些算法采用分治略:

 

1)堆排序算

 

2)二路归并序算法

 

3)折半查找

 

4)顺序查找

 

7.适合行计算的问题通表现出哪些特征

 

8.设有两个复数x=a+biy=c+di。复数乘积xy 可以使4 次乘法来完成xy=(ac-bd)+(ad+bc)i计一个仅用3 法来计算乘积xy 的方法。

 

9.4 数组abc d,都已经排好序说明找出这4 组的交集的方法。10.一个算法,采用分治法求一个数序列中的最大最小元素。

 

11.一个算法,采用分治法求x

 

12.假设二叉采用二叉链存储结构进行存储。计一个算法采用治法求一棵二叉bt 的高度。

 

13.假设二叉采用二叉链存储结构进行存储。计一个算法采用治法求一棵二叉bt 中度为2 点个数。

 

14.有一种二排序树,其定义是空树是一棵二排序树,若不空左子树中所有结点值小于根结点,右子树中所有点值大于根结点,并且左右子树是二叉排序树。现在该二叉排序采用二叉链存储采用分治法设计找值为x 的结点址,并分析算法的最好的平均时复杂度。

 

22

 

 

 

 

1

 

概论

 

 

15.设有n 不相同的整数,递增顺序存放在数组a[0..n-1],若存在一个下标i0i<n),使得a[i]=i。设计一个算法以O(log2n)时间找到这个i

 

16.模仿二分查找过程设计一个三查找算法。分析其时间复杂度。

 

17.对于1 的正整数n可以分解为n=x1*x2**xm,其中xi2例如,n=12 8 种不同的分式:12=1212=6*212=4*312=3*412=3*2*212=2*612=2*3*212=2*2*3,设计一个算法求n 不同分解式个数

 

18.设计一个基BSP 模型的并算法,假设有p 处理器,计算整数组a[0..n-1]的所有元素之和并分析算法的时复杂度。

 

1.3.2练习题参考答

 

1.答:C

 

2.答:D

 

3.答:a[]={12345}为例说明。选项A中在查找5 现死循环。选项B 中在查找5 时返-1。选项C 中在5 时返回-1D 正确。

 

4.答:无序序列a[low..high]行快速排序,整排序为大问题。选择其中一个基准base=a[i](通常以序列中第一个元素为基),将所有小等于base 的元素移到它的前面,所大于等于base 素移动到它的后,即将基准归位a[i],这样产a[low..i-1]a[i+1..high]个无序序列,它的排序为小问。当a[low..high]列只有一个元素或者空时对应递归出

 

所以快速排序算就是采用分治策,将一个大问分解为两个问题来求解。由于元素都a 数组中,其并过程是自然产的,不需要特别计。

 

5.答:此时快排序对应的递归高度为O(n)一次划分对应的时间为O(n)以整个排序时间O(n)

 

6.答:中二路归并排序折半查找算法采分治策略。

 

7.答:并行计算的问通常表现出以下征:

 

1)将工作分成离散部分,有于同时解决。例,对于分治法设的串行算法,可以将各个立的子问题并行解,最后合并成个问题的解,从转化为并行算法。

 

2)随时并及地执行多个程序令。

 

3)多计算资下解决问题的耗要少于单个计算源下的耗时。

 

8.答:xy=(ac-bd)+((a+b)(c+d)-ac-bd)i由此可见,这样xy只需要3次乘法(即acbd (a+b)(c+d)乘法运算)。

 

9.采用基本的二路并思路,先求ab 的交集ab求出cd 的交集cd最后求出ab cd的交集,即为最后的结果。也以直接采用4 并方法求解。

 

10.解:采用似求求一个整数序列中的最大次元素的分治法思。对应的程序如下:

 

#include

 

#define max(x,y)((x)>(y)?(x):(y))

 

#define min(x,y)((x)<(y)?(x):(y))

 

23

 

 

 

 

算法设计

 

voidMaxMin(inta[],intlow,inthigh,int&maxe,int&mine)

 

//a最小

 

 

{if (low==high)

 

{maxe=a[low];

 

mine=a[low];

 

}

 

else if (low==high-1)

 

{maxe=max(a[low],a[high]);

 

mine=min(a[low],a[high]);

 

}

 

else

 

{int mid=(low+high)/2;

 

//只有一个元素

 

//只有两个元素

 

//有两个以上元素

 

 

int lmaxe,lmine;

 

MaxMin(a,low,mid,lmaxe,lmine);

 

int rmaxe,rmine;

 

MaxMin(a,mid+1,high,rmaxe,rmine);

 

maxe=max(lmaxe,rmaxe);

 

mine=min(lmine,rmine);

 

}

 

}

 

voidmain()

 

{int a[]={4,3,1,2,5};

 

int n=sizeof(a)/sizeof(a[0]);

 

int maxe,mine;

 

MaxMin(a,0,n-1,maxe,mine);

 

printf("Max=%d, Min=%d\n",maxe,mine);

 

}

 

上述程序的执行果如图1.21 所示

 

 

1.21

 

程序执行结果

 

 

11.f(xn)=x,采用分治法解对应的递归模如下:

 

 

f(xn)=x

 

f(xn)=f(xn/2)*f(xn/2)

 

f(xn)=f(x(n-1)/2)*f(x(n-1)/2)*x对应的递归程序下:#include

 

doublesolve(doublex,intn)

 

{double fv;

 

if (n==1) returnx;

 

if (n%2==0)

 

{fv=solve(x,n/2);

 

return fv*fv;

 

}

 

n=1 n 为偶数时n 为奇数时

 

//x^n

 

24

 

 

 

 

1

 

else

 

{fv=solve(x,(n-1)/2);

 

return fv*fv*x;

 

}

 

}

 

voidmain()

 

{double x=2.0;

 

printf("求解结果:\n");

 

for (int i=1;i<=10;i++)

 

printf("%g^%d=%g\n",x,i,solve(x,i));

 

}

 

上述程序的执行果如图1.22 所示

 

概论

 

 

1.22

 

程序执行结果

 

 

12.f(bt)返回二叉树bt 的高度,对应递归模型如下:

 

 

f(bt)=0

 

f(bt)=MAX{f(bt->lchild)f(bt->rchild)}+1对应的程序如下

 

#include "Btree.cpp"

 

intHeight(BTNode*bt)

 

{if (bt==NULL)return 0;

 

int lh=Height(bt->lchild);

 

int rh=Height(bt->rchild);

 

if (lh>rh) returnlh+1;

 

else return rh+1;

 

}

 

voidmain()

 

{BTNode *bt;

 

Int a[]={5,2,3,4,1,6};

 

Int b[]={2,3,5,1,4,6};

 

int n=sizeof(a)/sizeof(a[0]);

 

bt=CreateBTree(a,b,n);

 

bt=NULL

 

其他情况

 

//包含二叉树的基运算算法//叉树bt

 

//子问题1

 

//子问题2

 

//合并

 

//ab构造二叉bt

 

 

printf("二叉树bt:");DispBTree(bt);printf("\n"); printf("bt的高度:%d\n",Height(bt));

 

 

DestroyBTree(bt);

 

//销毁树bt

 

 

}

 

 

25

 

 

 

 

算法设计

 

 

上述程序的执行果如图1.23 所示

 

 

1.23

 

程序执行结果

 

 

13.f(bt)返回二叉树bt 中度为2 的结个数,对应的递模型如下:

 

 

f(bt)=0

 

f(bt)=f(bt->lchild)+f(bt->rchild)+1f(bt)=f(bt->lchild)+f(bt->rchild)

 

对应的算法如下

 

#include "Btree.cpp"

 

intNodes(BTNode*bt)

 

{int n=0;

 

bt=NULL

 

btNULL bt 分支结点其他情况

 

//包含二叉树的基运算算法//bt2

 

 

if (bt==NULL) return0;

 

if (bt->lchild!=NULL&& bt->rchild!=NULL)

 

n=1;

 

return Nodes(bt->lchild)+Nodes(bt->rchild)+n;

 

}

 

voidmain()

 

{BTNode *bt;

 

Int a[]={5,2,3,4,1,6};

 

Int b[]={2,3,5,1,4,6};

 

int n=sizeof(a)/sizeof(a[0]);

 

 

bt=CreateBTree(a,b,n);

 

//ab构造二叉bt

 

 

printf("二叉树bt:");DispBTree(bt);printf("\n"); printf("bt中度为2的结点个数:%d\n",Nodes(bt));

 

 

DestroyBTree(bt);

 

//销毁树bt

 

 

}

 

上述程序的执行果如图1.24 所示

 

 

1.24

 

程序执行结果

 

 

14.解:f(btx)返回在二叉排序树bt 的值为x 结点的址,若没有找到返空,对应的递归型如下:

 

 

f(btx)=NULL

 

f(btx)=bt

 

f(btx)=f(bt->lchildx)

 

bt=NULL

 

btNULL x=bt->datax>bt->data

 

26

 

 

 

 

1

 

概论

 

 

f(btx)=f(bt->rchildx) 对应的程序如下

 

#include "Btree.cpp"

 

x->data

 

//包含二叉树的基运算算法

 

 

BTNode*Search(BTNode*bt,Int x)//二叉排序树bt的值为x结点{if (bt==NULL)return NULL;

 

if (x==bt->data)return bt;

 

if (xdata) returnSearch(bt->lchild,x);

 

else return Search(bt->rchild,x);

 

}

 

voidmain()

 

{BTNode *bt;

 

Int a[]={4,3,2,8,6,7,9};

 

Int b[]={2,3,4,6,7,8,9};

 

int n=sizeof(a)/sizeof(a[0]);

 

 

bt=CreateBTree(a,b,n);

 

//构造一棵二叉排bt

 

 

printf("二叉排序bt:");DispBTree(bt); printf("\n");int x=6;

 

BTNode *p=Search(bt,x);

 

if (p!=NULL)

 

printf("找到结点:%d\n",p->data);

 

else

 

printf("没有找到\n",x);

 

 

DestroyBTree(bt);

 

//销毁树bt

 

 

}

 

上述程序的执行果如图1.25 所示

 

 

1.25

 

程序执行结果

 

 

Search(btx)算法采的是减治法,最的情况是某个结左右子树高度大致相同,其平均执行时间T(n)如下:

 

 

T(n)=1

 

T(n)=T(n/2)+1

 

n=1

 

n>1

 

 

可以推出T(n)=O(log2n),其中n 为二排序树的结点个

 

15.解:二分查找方法。a[i]=i 时表示该元在有序非重复序a 中恰好第i 对于序列a[low..high]mid=(low+high)/2a[mid]=mid 表示找该元素;若a[mid]>mid说明右区间的所元素都大于其位,只能在左区间查找;若a[mid]说明左区间的所有元素都小其位置,只能在间中查找。对的程序如下:

 

#include

 

 

intSearch(inta[],intn)

 

{int low=0,high=n-1,mid;

 

//使得a[i]=i

 

27

 

 

 

 

算法设计

 

while (low<=high)

 

{mid=(low+high)/2;

 

if (a[mid]==mid)//查找到样的元素

 

return mid;

 

else if (a[mid]//这样的素只能在右区间中出现 low=mid+1;

 

 

else

 

//这样的元素只能左区间中出现

 

 

high=mid-1;

 

}

 

return -1;

 

}

 

voidmain()

 

{int a[]={-2,-1,2,4,6,8,9};

 

int n=sizeof(a)/sizeof(a[0]);

 

int i=Search(a,n);

 

printf("求解结果\n");

 

if (i!=-1)

 

printf("存在a[%d]=%d\n",i,i);else

 

printf("不存在\n");

 

}

 

上述程序的执行果如图1.26 所示

 

 

1.26

 

程序执行结果

 

 

16.解:有序序列a[low..high]若元素个数少于3个,直接查找若含有更多的元素,将其分为a[low..mid1-1]a[mid1+1..mid2-1]a[mid2+1..high]子序列,对每子序列递归查找,算的时间复杂度为O(log3n),属于O(log2n)级别。对应的算法如下:

 

#include

 

 

intSearch(inta[],intlow,inthigh,intx) {if (high

 

return -1;

 

else if (high==low)

 

{if (x==a[low])

 

return low;

 

else

 

return -1;

 

}

 

if (high-low<2)

 

{if (x==a[low])

 

return low;

 

else if (x==a[low+1])

 

return low+1;

 

else

 

//查找

 

//序列中没有元素

 

//序列中只有1

 

//序列中只有2

 

 

28

 

 

 

 

1

 

概论

 

 

return -1;

 

}

 

int length=(high-low+1)/3;

 

int mid1=low+length;

 

int mid2=high-length;

 

if (x==a[mid1])

 

return mid1;

 

else if (x

 

return Search(a,low,mid1-1,x);

 

else if (x==a[mid2])

 

return mid2;

 

else if (x

 

return Search(a,mid1+1,mid2-1,x);

 

else

 

return Search(a,mid2+1,high,x);

 

}

 

voidmain()

 

{int a[]={1,3,5,7,9,11,13,15};

 

int n=sizeof(a)/sizeof(a[0]);printf("求解结果\n");

 

int x=13;

 

int i=Search(a,0,n-1,x);

 

if (i!=-1)

 

printf("a[%d]=%d\n",i,x);

 

else

 

printf("不存在%d\n",x);

 

int y=10;

 

int j=Search(a,0,n-1,y);

 

if (j!=-1)

 

printf("a[%d]=%d\n",j,y);

 

else

 

printf("不存在%d\n",y);

 

}

 

上述程序的执行果如图1.27 所示

 

//每个子序列的长

 

 

1.27

 

程序执行结果

 

 

17.f(n)表示n的不同分解式个数有:f(1)=1,作为递归

 

f(2)=1,分解式为2=2

 

f(3)=1,分解式为3=3

 

f(4)=2,分解式为4=44=2*2

 

29

 

 

 

 

算法设

 

f(6)=3,分解式为6=66=2*36=3*2,即f(6)=f(1)+f(2)+f(3)

 

以此类推,可以f(n)n 的所有数的不同分解式数之和,即f(n)= (/)。对应的程序如

 

#include

 

#define MAX 101

 

 

intsolve(int n)

 

{if (n==1) return1; else

 

{int sum=0;

 

//n分解式个数

 

 

for (int i=2;i<=n;i++)

 

if (n%i==0)

 

sum+=solve(n/i);

 

return sum;

 

}

 

}

 

voidmain()

 

{int n=12;

 

int ans=solve(n);

 

printf("结果: %d\n",ans);

 

}

 

上述程序的执行果如图1.28 所示

 

1.28

 

程序执行结果

 

 

18.对应的并行算法下:

 

intSum(inta[],ints,intt,intp,int i)//理器i执行{int j,s=0;

 

for (j=s;j<=t;j++)

 

s+=a[j];

 

return s;

 

}

 

intParaSum(inta[],ints,intt,intp,int i)

 

{int sum=0,j,k=0,sj;

 

 

for (j=0;j

 

{sj=Sum(a,k,k+n/p-1,p,j);

 

k+=n/p;

 

}

 

sum+=sj;

 

return sum;

 

//for循环的各个问题并行执行

 

 

}

 

每个处理器的执时间为O(n/p),同开销为O(p),所该算法的时间复度为O(n/p+p)

 

30

 

 

 

 

1

 

概论

 

 

1.44 蛮力法

 

1.4.1练习题

 

1.简要较蛮力法和分治

 

2.在采蛮力法求解时什情况下使用递归

 

3.考虑下面个算法,它求的是数组a 中大小差最小的两个元的差。请对这个算法做尽可能多改进。

 

#define INF 99999

 

 

#define abs(x) (x)<0?-(x):(x)

 

intMindif(inta[],intn)

 

{int dmin=INF;

 

for (int i=0;i<=n-2;i++)

 

//求绝对值宏

 

 

for (int j=i+1;j<=n-1;j++)

 

{int temp=abs(a[i]-a[j]);

 

if (temp

 

dmin=temp;

 

}

 

return dmin;

 

}

 

4.给定一个整数A=(a0a1an-1),若i<jai>aj,则<aiaj>就为个逆序对。例如数组31452逆序对有<31><32><42><52>。设计一个算法采用蛮力A 中逆序对的数即逆序数。

 

5.于给定的正整数nn>1,采用蛮力1!+2!++n!改进该算法提高率。

 

6.有一群鸡一群兔,它们的只数相同,它们脚数都是三位数且这两个三位数的各位数字只能012345。设计一个算法用蛮力法求鸡兔的只数各是多少?它们的脚数是多少?

 

7.有一个三数,个位数字比百位数字大,而位数字又比十位字大,并且各位数字之和等于各数字相乘之积,计一个算法用穷法求此三位数。

 

8.某年级的同集体去公园划船如果每只船坐10 ,那么多出2 位;如果每只船多坐2 人,么可少租1 只船设计一个算法用力法求该年级的多人数?

 

9.已知:若个合数的质因数分解式逐位相加和等于其本身逐相加之和,则称这个数为Smith 。如4937775=3*5*5*65837,而3+5+5+6+5+8+3+7=424+9+3+7+7+7+5=42,所以4937775 Smith 求给定一个正整N,求大于N Smith 数。

 

输入:若干个case每个case 一行代正整数N,输入0 表示结束

 

输出:大于N 最小Smith

 

输入样例:

 

4937774

 

0

 

样例输出:

 

31

 

 

 

 

算法设计

 

4937775

 

10.求解涂盘问题。小易有一块n*n 的棋盘棋盘的每一个格都为黑色或者白色,小易现在要他喜欢的红色去画棋盘。小易会出棋盘中某一列拥有相同颜色的最大的区域去涂,帮助小易算算会涂画多少个棋

 

输入描述:输入据包括n+1 行:一行为一个整数n1n50),即棋盘的小,接下来的n 每行一个字符串示第i 行棋盘的色,'W'表示白色,'B'表示黑色

 

输出描述:输出易会涂画的区域小。

 

输入例子:

 

3

 

BWW

 

BBB

 

BWB

 

输出例子:

 

3

 

11.一个含nn>1整数元素的a,所元素不相同,采蛮力法求出a 有元素的全排列

 

1.4.2练习题参考答

 

1.答:蛮力是一种简单直接地解决问题的方,适用范围广,能解决几乎所有问题的一般性方,常用于一些非基本、但又十分要的算法(排序查找、矩阵乘法和字符串匹配等),蛮力法主解决一些规模小或值低的问题,可作为同样问题的高效算法的一个准。而分治法采分而治之思路,一个复杂的问题成两个或更多的相同或相似的子题,再把子问题成更小的子问题到问题解决。分法在求解问题时,通常性能比力法好。

 

2.答:如果蛮力法求解的问题可以分解为若个规模较小的相子问题,此时可以采用递归来实算法。

 

3.解:上述算的时间复杂度为O(n),采的是最基本的蛮力法。可以先a中元素递增排序,然依次比较相邻元的差,求出最小,改进后的算法下:

 

#include

 

#include

 

using namespace std;

 

intMindif1(inta[],intn)

 

 

{sort(a,a+n);

 

int dmin=a[1]-a[0];

 

for (int i=2;i

 

{int temp=a[i]-a[i-1];

 

if (temp

 

dmin=temp;

 

}

 

return dmin;

 

}

 

//递增排序

 

32

 

 

 

 

1

 

概论

 

 

上述算法的主要间花费在排序上算法的时间复杂O(nlog2n)

 

4.解:用两循环直接判断是否为逆序对,法的时间复杂度为O(n2),比第3实验3 算法的性差。对应的算法下:

 

 

intsolve(inta[],intn)

 

{int ans=0;

 

for (int i=0;i

 

for (int j=i+1;j

 

if (a[i]>a[j])

 

ans++;

 

return ans;

 

//序数

 

 

}

 

5.解:接采用蛮力法求算法如下:

 

 

longf(intn)

 

{long fn=1;

 

for (int i=2;i<=n;i++)

 

fn=fn*i;

 

return fn;

 

}

 

longsolve(intn)

 

{long ans=0;

 

for (int i=1;i<=n;i++)

 

ans+=f(i);

 

return ans;

 

//n!

 

//1!+2!+…+n!

 

 

}

 

实际上,f(n)=f(n-1)*nf(1)=1,在求f(n)时可以利用f(n-1)的结果。改后的算法如

 

 

下:

 

 

longsolve1(intn)

 

{long ans=0;

 

long fn=1;

 

for (int i=1;i<=n;i++)

 

{fn=fn*i;

 

ans+=fn;

 

}

 

return ans;

 

//1!+2!+…+n!

 

 

}

 

6.解:脚数为y=abc,兔数为z=def,有1ad50bcef5,采6 重循环,求鸡只数x1=y/2y 2的倍数),兔只数x2=z/4z 4 的倍数),当x1=x2 时输出结。对应的程序如

 

#include

 

voidsolve()

 

{int a,b,c,d,e,f;

 

int x1,x2,y,z;

 

for (a=1;a<=5;a++)

 

for (b=0;b<=5;b++)

 

for (c=0;c<=5;c++)

 

33

 

 

 

 

算法设计

 

for (d=1;d<=5;d++)

 

for (e=0;e<=5;e++)

 

for (f=0;f<=5;f++)

 

{y=a*100+b*10+c;

 

z=d*100+e*10+f;

 

if (y%2!=0 || z%4!=0)

 

continue;

 

x1=y/2;

 

x2=z/4;

 

if (x1==x2)

 

//鸡脚数

 

//兔脚数

 

//鸡只数

 

//兔只数

 

 

printf("鸡只数:%d,兔只数:%d,鸡脚数:%d, 兔脚数:%d\n",x1,x2,y,z);

 

}

 

}

 

voidmain()

 

{printf("结果\n");

 

solve();

 

}

 

上述程序的执行果如图1.29 所示

 

 

1.29程序执行

 

7.设该三数为x=abc,有1a90bc9满足c>aa>ba+b+c=a*b*c。对的程序如下:

 

#include

 

voidsolve()

 

{int a,b,c;

 

for (a=1;a<=9;a++)

 

for (b=0;b<=9;b++)

 

for (c=0;c<=9;c++)

 

{if (c>a && a>b&&a+b+c==a*b*c)

 

printf("%d%d%d\n",a,b,c);

 

}

 

}

 

voidmain()

 

34

 

 

 

 

1

 

概论

 

 

{

 

printf("求解结果\n");solve();

 

 

}

 

上述程序的执行果如图1.30 所示

 

 

1.30程序执行

 

8.解:该年级的人数为x,租船数为y。因为每只船坐10 正好多出2 个座,则x=10*y-2;因为每船多坐2 人即12 时可少租1 只船没有说恰好全部位占满),有x+z=12*(y-1)z 示此时空出的座位,显然z<12y 1 100实际上y取更大范围的结果是相同的)、z011 ,求出最大的x 。对应的程序如

 

#include

 

intsolve()

 

{int x,y,z;

 

for (y=1;y<=100;y++)

 

for (z=0;z<12;z++)

 

if (10*y-2==12*(y-1)-z)

 

x=10*y-2;

 

return x;

 

}

 

voidmain()

 

{printf("结果\n");

 

printf("最多人:%d\n",solve());

 

}

 

上述程序的执行果如图1.31 所示

 

 

1.31程序执行

 

9.解:用蛮力法求出一正整数n的各位数字和sum1n的所有质因数的数字和sum2,若sum1=sum2,即为Smitch数。从用户输入的n开始枚举,若是Smitch 数,输出,本次束,否则n++继续找大于n 的最小Smitch数。对应的整程序如下:

 

#include

 

 

intSum(intn)

 

{int sum=0;

 

while (n>0)

 

//n数字

 

 

35

 

 

 

 

算法设计

 

{sum+=n%10;

 

n=n/10;

 

}

 

return sum;

 

}

 

boolsolve(intn)//n是否Smitch

 

{int m=2;

 

int sum1=Sum(n);

 

int sum2=0;

 

while (n>=m)

 

{if (n%m==0)//找到一个质因m

 

{n=n/m;

 

sum2+=Sum(m);

 

}

 

else

 

m++;

 

}

 

if (sum1==sum2)

 

return true;

 

else

 

return false;

 

}

 

voidmain()

 

{int n;

 

while (true)

 

{scanf("%d",&n);

 

if (n==0) break;

 

while (!solve(n))

 

n++;

 

printf("%d\n",n);

 

}

 

}

 

10.解:采用蛮力,统计每一列相邻相同颜色的棋个数countj,在countj中求最大值。对应的程如下:

 

#include

 

#define MAXN 51

 

//问题表示

 

int n;

 

char board[MAXN][MAXN];

 

 

intgetMaxArea()

 

{int maxArea=0;

 

for (int j=0; jj++){int countj=1;

 

//法求解算法

 

 

for (int i=1; ii++)//j列中相同颜色相邻棋格个数 {if (board[i][j]==board[i-1][j])

 

countj++;

 

else

 

countj=1;

 

}

 

36

 

 

 

 

1

 

概论

 

 

if (countj>maxArea)

 

maxArea=countj;

 

}

 

return maxArea;

 

}

 

intmain()

 

{scanf("%d",&n);

 

for (int i=0;i

 

scanf("%s",board[i]);

 

printf("%d\n",getMaxArea());

 

return 0;

 

}

 

11.解:与《程》中求全排列类似,但需要将1n 的全排列改按下标0n-1 a 的全排列(标从0 开始)。采用非递的程序如下:

 

#include

 

#include

 

using namespace std;

 

 

vector> ps;

 

//存放全排列

 

 

voidInsert(vectors,inta[],inti,vector> &ps1)//个集合元素中间插入i得到ps1

 

{vectors1;

 

vector::iteratorit;

 

 

for (int j=0;j<=i;j++)

 

{s1=s;

 

it=s1.begin()+j;

 

s1.insert(it,a[i]);

 

ps1.push_back(s1);

 

}

 

}

 

voidPerm(inta[],intn)

 

{vector> ps1;

 

vector>::iterator it;

 

vector s,s1;

 

s.push_back(a[0]);

 

ps.push_back(s);

 

for (int i=1;i

 

{ps1.clear();

 

for (it=ps.begin();it!=ps.end();++it)

 

Insert(*it,a,i,ps1);

 

ps=ps1;

 

}

 

}

 

voiddispps()

 

//s(i个整数)每个位置插入a[i] //求出插入位置

 

//插入整数a[i]

 

//添加到ps1

 

//a[0..n-1]全排

 

//临时存放子排列

 

//全排列迭代器

 

//添加{a[0]}集合

 

//循环添加a[1]a[n-1]

 

//ps1存放插入a[i]的结果

 

//在每个集合元素间插入a[i]得到ps1 //全排列ps

 

 

{vector>::reverse_iteratorit;//全排列的反向代器

 

 

vector::iteratorsit;

 

//排列集合元素迭

 

 

你可能感兴趣的:(算法设计与分析(李春保)练习题答案v1)