算法作业和期末复习题.docx
《算法作业和期末复习题.docx》由会员分享,可在线阅读,更多相关《算法作业和期末复习题.docx(13页珍藏版)》请在冰豆网上搜索。
算法作业和期末复习题
1.给出递推公式
x(n)=x(n-1)+n,x(0)=0对应的通项公式计算过程?
解:
X(n)-X(n-1)=n
X(n-1)-X(n-2)=n-1
…………
X
(1)-X(0)=1
X(n)-X(0)=(n+1)n\2
X(n)=(n+1)n\2
2.、、之间的区别与联系
描述增长率的上限上限值越低,结果越有价值。
用来表示算法的精确阶
描述增长率的下限下限值越高越有价值。
联系:
只要当考察问题规模充分大时,算法中基本语句的执行次数在渐近意义下的阶,通常使用3种等渐近符号。
3.什么是数据结构,什么是算法,两者有什么关系?
数据结构:
是指相互之间存在一定关系的数据元素的集合。
算法:
是对特定问题求解步骤的一种描述是指令的有限序列。
程序=算法+数据结构
5.举例说明分治法、动态规划法和贪心法适用范围,及三者之间的区别。
答:
分治法:
适用于原问题可划分为子问题时如汉诺塔问题(循环赛,最近对,棋盘覆盖等)
动态规划:
当原问题可分解为子问题并且问题重叠并且具有最优子结构时可用动态规划法,如TSP问题(多端最短路径问题,0/1背包问题等)
贪心:
当一个问题具有最优子结构性质且具有贪心选择性时可用贪心算法,如最小生成树问题(背包问题,活动安排问题等)
在分治法的基础上,满足最优子结构性质才能用动态规划,在动态规划可行的基础上满足贪心选择性才能用贪心。
6.简述分治法、贪心法、蛮力法、回溯法、减治法的设计思想。
分治:
建一个难以直接解决的大问题划分成一些规模较小的子问题,以便各个击破,分而治之。
贪心把一个问题分解为一系列较简单的局部最优选择,每一步选择都是对当前解的一个扩展,直到获得问题的完整解。
(指根据当前已有信息做出选择,不从整体最优考虑,只选择局部最优
蛮力:
采用一定的策略将待求解问题的所有元素依次处理一次,从而找出问题的解。
回溯:
只构造可能解的一部分,然后评估这个部分解,如果这个部分解有可能导致一个完全解,则对其进一步构造,否则,就不必继续构造这个解了。
减治:
把一个大问题划分为若干子问题,但些子问题不需要分别求解,只需求解其中那个一个子问题。
7.举例说明分治法和减治法的在设计上区别与联系。
分治法是将一个大问题分解为若干子问题分别求解,而减治法是只求解部分子问题。
在排序问题中,分治法用用快速排序,以轴值为基准划分序列,再求每个子集递归序列,最后合并并操作。
减治法则用选择问题算法,先选定轴值并划分,比轴值小的在左侧,比轴值大的在右侧,选择问题的查找区间减少一半,划分后只需处理一个子序列。
8.简述什么是欧拉回路,TSP问题,哈密顿回路问题。
欧拉回路:
图G的一个回路,若它恰它通过G中每条边一次,则称该回路为欧拉回路。
TSP:
从图的一个顶点出发,各个定点只能经历并访问一次,最后回到原点且使路径最短。
哈密顿回路:
从一个城市出发,经过每一个城市恰好一次,然后回到出发城市。
1.给出应用动态规划法设计算法的一般步骤,并用动态规划法求下面多段图中从顶点0到顶点15的最短路径,写出求解过程。
解:
d(0,9)=min{c01+d(1,9),c02+d(2,9),c03+d(3,9)}
d(1,9)=min{c14+d(4,9),c15+d(5,9)}
d(2,9)=min{c24+d(4,9),c25+d(5,9),c26+d(6,9)}
d(3,9)=min{c35+d(5,9),c36+d(6,9)}
d(4,9)=min{c47+d(7,9),c48+d(8,9)}
d(5,9)=min{c57+d(7,9),c58+d(8,9)}
d(0,9)=min{c67+d(7,9),c68+d(8,9)}
d(7,9)=c79=7(7→9)
d(8,9)=c89=3(8→9)
d(6,9)=min{6+7,5+3}=8(6→8)
d(5,9)=min{8+7,6+3}=9(5→8)
d(4,9)=min{5+7,6+3}=9(4→8)
d(3,9)=min{4+9,7+8}=13(3→5)
d(2,9)=min{6+9,7+9,8+8}=15(2→4)
d(1,9)=min{9+9,8+9}=17(1→5)
d(0,9)=min{4+17,2+15,3+13}=16(0→3)
最后得最短路径为0→3→5→8→9长度为16。
2.有4个物品,其重量分别为(4,7,5,3),物品的价值分别为(40,42,25,12),背包容量为10。
试设计3种贪心策略,并给出在每种贪心策略下背包问题的解。
重量最轻:
装入143.总价值:
40+12+25*3/5=67
价值最大:
装入1,2。
总价值:
40*3/4+42=72
性价比最小:
装入1,2.总价值:
40+6/7*42=76
3.给出{2313496311928}采用快速排序思想进行排序时一次划分的过程示意图。
1913496312328
1913236314928
1913623314928
1.给定数组A[n],存储n个实数,试设计一个算法,在最坏情况下用最少比较次数找出该数组中元素的最大值和最小值,并说明采用了何种算法设计思想,其最坏比较多少次。
求数组的最大值和最小值
a)问题
求给定数组a[0:
n-1]的最大值和最小值。
要求:
最坏情况下用3n/2-2次比较
b)分析
分治法,把数组分成n/2组,每组2个数。
然后每组的两个数进行一次比较,确定出每组的最大数和最小数保存在数组MAX[i]和MIN[i]中,这样总共进行了n/2次比较。
最后从MAX[i]中找出最大的数MAX,从MIN[i]中找出最小的数MIN,需要2*(n/2-1)次比较。
MAX和MIN就是原来问题的解。
总比较次数为3n/2–2次
该算法在任何情况下进行的比较次数都是3n/2–2,固最差情况也是3n/2–2.
c)编程实现
Quotedfrom求数组的最大值和最小值:
//two15.java
//该算法在任何情况下的比较次数都是3N/2-2。
所以在最差情况下也是3N/2-2
importjavax.swing.JOptionPane;
publicclasstwo15{
publicstaticvoidmain(Stringargs[])
{inta[]=newint[50];//
intmin[]=newint[25];//
intmax[]=newint[25];//
intn=0,i=0,k=1;
Stringnum;
Stringaa[]=newString[50];
num=JOptionPane.showInputDialog("enterthetotalnumofthearray");
n=Integer.parseInt(num);//单个数不进行比较
if(n!
=1){
for(i=0;i {aa[i]=JOptionPane.showInputDialog("请输入数组的每个元素");
a[i]=Integer.parseInt(aa[i]);}
//用分治法把N个数分成2/N组每组两个进行比较,把小的放在MIN,大的放在MAX
//最差情况下比较N/2次
for(i=1;i<(n/2)*2;i=i+2)
{ if(a[i-1]<=a[i])
{ min[k-1]=a[i-1];max[k-1]=a[i];k++;
}else
{min[k-1]=a[i];max[k-1]=a[i-1];k++;
}}
/*在MAX中找出最大的,在MIN中找出最小的
*最差情况下比较2*(N/2-1)次*/
intmaxm=max[0],minm=min[0];
for(k=1;k { if(max[k]>maxm)maxm=max[k];
if(min[k] }
if(n%2!
=0)//N为奇数时,还要和最后一个数比较
{if(a[n-1]>maxm)maxm=a[n-1];
if(a[n-1] JOptionPane.showMessageDialog(null,
"最大的数是"+maxm+"最小的数是"+minm,
"result",JOptionPane.INFORMATION_MESSAGE); } elseJOptionPane.showMessageDialog(null,
"一个数无须查找","警告!
"
,JOptionPane.INFORMATION_MESSAGE); }}
2.描述贪心法的求解过程,给出基于最近邻点策略采用贪心法求解TSP问题伪代码,并分析该算法的时间性能。
伪代码:
1.P={};2.V=V-{u0};u=u0;//从顶点u0出发;3循环直到集合P中包含n-1条边3.1查找与顶点u邻接的最小代价边(u,v)并且v属于集合V;3.2P=P+{(u,v)};3.3V=V—{v};3.4u=v;//从顶点v出发继续求解
3.设计算法实现求数组中相差最小的两个元素(称为最接近数)的差。
算法MinDistance(A[0..n-1])
//输入:
数组A[0..n-1]
//输出:
thesmallestdistancedbetweentwoofitselements
算法4.10——最近对问题
intClosestPoints(S)//S为平面上n个点的坐标组成的集合
{1.if(n<2)return∞;
2.m=S中各点x坐标的中位数;
3.构造S1和S2,使得S1中点的x坐标小于m,S2中点的x坐标大于m;
4.d1=ClosestPoints(S1);d2=ClosestPoints(S2);
5.d=min(d1,d2);
6.构造P1和P2,使得P1是S1中点的x坐标与m的距离小于d的点集,P2是S2中点的x坐标与m的距离小于d的点集;
7.将P1和P2中的点按y坐标升序排列;
8.对P1中的每一个点p,在P2中查找与点p的y坐标小于d的点,并求出其中的最小距离d';
9.returnmin(d,d');}
4.有n枚硬币,其中有一枚硬币是假币,且假币的重量较轻,通过一架天平找出假币,。
。
比较次数最少。
答:
减治算法。
先把n枚硬币分成两组,每组有[2/n]枚硬币,如果n为奇数就留下一枚硬币,然后把两组硬币分别放到天平的两端。
如果两组硬币重量相同,那么留下的硬币就是假币;否则,用同样的方法对较轻的那组硬币进行同样处理,应为假币一定在较轻的那组里.
#include
#include
usingnamespacestd;
intCheck_out(intB[],intn);
intmain()
{intn,n1;
cout<<"注意:
\n"<<"真硬币用1表示,假硬币用0或2表示.\n";
cout<<"0表示假硬币比真硬币轻,2表示假硬币比真硬币重。
\n";
cout<<"请输入硬币的总个数:
(请确定你输入的总个数大于2,否则不能判断出假的硬币)\n";
cin>>n;
int*B=newint[n];
cout<<"请输入硬币:
";
for(inti=0;i{cin>>n1;while(n1!
=0&&n1!
=2&&n1!
=1)
{cout<<"对不起,你的输入有误,请重新输入:
";
cin>>n1;
}B[i]=n1;
}if((B[0]+B[1]+B[2])==(B[3]+B[4]+B[5]))
{if(B[0]==B[6])
{cout<<"第8枚是假币";//鏁扮粍涓槸con[7]}
else{cout<<"第7枚是假币";;}
}else{if((B[0]+B[1])==(B[2]+B[6]))
{if((B[3]+B[4])==(B[7]+B[6]))
{cout<<"第6枚是假币";;
}else
{if(B[3]==B[6])
{cout<<"第5枚是假币";;
}else
{cout<<"第4枚是假币";;
}}}
else{if((B[0]+B[1])==(B[7]+B[6]))
{cout<<"第3枚是假币";;
}else
{if(B[0]==B[6]){
cout<<"第2枚是假币";;
}else{
cout<<"第1枚是假币";;}}}}
system("PAUSE");
returnEXIT_SUCCESS}
5.一个农夫带着一条狼、一只羊和一筐菜。
。
并设计算法求解。
解:
带羊到对岸,空手回本岸,带狼到对岸,带羊回本岸,带菜到对岸,空手回本岸,带羊到对岸
#include
#include
#include
#defineMAX_STEP20
//index:
0-狼,1-羊,2-菜,3-农夫,value:
0-本岸,1-对岸
inta[MAX_STEP][4];
intb[MAX_STEP];
char*name[]=
{"空手","狼","带羊","带菜"};
voidsearch(intiStep)
{inti;
if(a[iStep][0]+a[iStep][1]+a[iStep][2]+a[iStep][3]==4)
{for(i=0;i{if(a[i][3]==0)
{printf("%s到对岸\n",name[b[i]+1]);}else
{printf("%s回本岸\n",name[b[i]+1]);}
}printf("\n");return;
}for(i=0;i{if(memcmp(a[i],a[iStep],sizeof(a[i]))==0)
{return;}
}if(a[iStep][1]!
=a[iStep][3]&&(a[iStep][2]==a[iStep][1]||a[iStep][0]==a[iStep][1]))
{return;
}for(i=-1;i<=2;i++)
{b[iStep]=i;
memcpy(a[iStep+1],a[iStep],sizeof(a[iStep+1]));
a[iStep+1][3]=1-a[iStep+1][3];
if(i==-1)
{search(iStep+1);
}elseif(a[iStep][i]==a[iStep][3])
{a[iStep+1][i]=a[iStep+1][3];
search(iStep+1);
}}}intmain(){search(0);
return0;}
6.已知某系统在通信联络中只可能出现八种字符,其概率分别为0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试设计其哈夫曼编码,并请画出其图形,说明其设计思想。
#include
#include
#defineN50/*叶子结点数*/
#defineM2*N-1/*树中结点总数*/
typedefstruct
{chardata[5];/*结点值*/
intweight;/*权重*/
intparent;/*双亲结点*/
intlchild;/*左孩子结点*/
intrchild;/*右孩子结点*/
}HTNode;
typedefstruct
{charcd[N];/*存放哈夫曼码*/
intstart;
}HCode;
voidCreateHT(HTNodeht[],intn)
{inti,k,lnode,rnode;
intmin1,min2;
for(i=0;i<2*n-1;i++)/*所有结点的相关域置初值-1*/
ht[i].parent=ht[i].lchild=ht[i].rchild=-1;
for(i=n;i<2*n-1;i++)/*构造哈夫曼树*/
{min1=min2=32767;/*lnode和rnode为最小权重的两个结点位置*/
lnode=rnode=-1;
for(k=0;k<=i-1;k++)
if(ht[k].parent==-1)/*只在尚未构造二叉树的结点中查找*/{if(ht[k].weight{min2=min1;rnode=lnode;
min1=ht[k].weight;lnode=k;}
elseif(ht[k].weight{min2=ht[k].weight;rnode=k;}}
ht[lnode].parent=i;ht[rnode].parent=i;ht[i].weight=ht[lnode].weight+ht[rnode].weight;ht[i].lchild=lnode;ht[i].rchild=rnode;}}
voidCreateHCode(HTNodeht[],HCodehcd[],intn)
{inti,f,c;
HCodehc;
for(i=0;i{hc.start=n;c=i;
f=ht[i].parent;
while(f!
=-1)/*循序直到树根结点*/{
if(ht[f].lchild==c)//处理左孩子结点
hc.cd[hc.start--]='0';
else/*处理右孩子结点*/
hc.cd[hc.start--]='1';
c=f;f=ht[f].parent;}
hc.start++;/*start指向哈夫曼编码最开始字符*/
hcd[i]=hc}}
voidDispHCode(HTNodeht[],HCodehcd[],intn)
{inti,k;
intsum=0,m=0,j;
printf("输出哈夫曼编码:
\n");/*输出哈夫曼编码*/
for(i=0;i{j=0;
printf("%s:
\t",ht[i].data);
for(k=hcd[i].start;k<=n;k++)
{printf("%c",hcd[i].cd[k]);
j++;}
m+=ht[i].weight;
sum+=ht[i].weight*j;
printf("\n");}
printf("\n平均长度=%g\n",1.0*sum/m);}
voidmain()
{intn=15,i;
char*str[]={"The","of","a","to","and","in","that","he","is","at","on","for","His","are","be"};
intfnum[]={1192,677,541,518,462,450,242,195,190,181,174,157,138,124,123};
HTNodeht[M];
HCodehcd[N];
for(i=0;i{strcpy(ht[i].data,str[i]);
ht[i].weight=fnum[i];}
printf("\n");
CreateHT(ht,n);
CreateHCode(ht,hcd,n);
DispHCode(ht,hcd,n);
printf("\n");}