算法与分析平时作业答案文档格式.docx
《算法与分析平时作业答案文档格式.docx》由会员分享,可在线阅读,更多相关《算法与分析平时作业答案文档格式.docx(14页珍藏版)》请在冰豆网上搜索。
3、定义:
给定一个自然数n,由n开始依次产生半数集set(n)中的元素如下:
1)nset(n);
2)在n的左边加上一个自然数,但该自然数不能超过最近添加的数的一半;
3)按此规则进行处理,直至不能再添加新的自然数为止。
例如set(n){6,16,26,126,36,136}。
其中共有6个元素。
半数集问题:
对于给定的n,求半数集set(n)中元素的个数。
半数集set(n)中元素个数的求解是个递归的过程。
设set(n)中的元素个数为f(n),则显然有递归表达式:
f(n)=1+刀f(i),i=1,2n/2。
即半数集set(n)元素个数
f(n)=1+f
(1)+f
(2)+...+f(floor(n/2)).用递推法求解。
C语言代码如下:
#include<
stdio.h>
#include<
stdlib.h>
intmain(){
intn;
inti,j,s;
intbuf[106];
char*in="
input.txt"
*out="
output.txt"
;
FILE*ip,*op;
if((ip=fopen(in,"
r"
))==NULL)return1;
if((op=fopen(out,"
w"
))==NULL)return2;
fscanf(ip,"
%d"
&
n);
fclose(ip);
buf[1]=1;
buf[2]=2;
buf[3]=2;
for(i=4;
i*2<
=n;
i++){
s=1;
for(j=1;
j<
=i/2;
j++){
s+=buf[j];
buf[i]=s;
=n/2;
fprintf(op,"
s);
fclose(op);
/*system("
pause"
);
*/
return0;
4、设计一个算法,找出由n个数组成的序列的最长单调递增子序列的长度。
答:
iostream.h>
#definem10
//快速排序
voidQuickSort(intR[],ints,intt){
inti=s,j=t;
inttmp;
if(s<
t){
tmp=R[s];
while(i!
=j){while(j>
i&
&
R[j]>
=tmp)j--;
R[i]=R[j];
while(i<
j&
R[i]<
=tmp)i++;
R[j]=R[i];
R[i]=tmp;
QuickSort(R,s,i-1);
QuickSort(R,i+1,t);
//找出最长公共子序列
voidLCSLength(intx[],inty[],intn,intc[m][m],intb[m][m]){
inti,j;
for(i=0;
i<
n;
i++){
c[0][i]=0;
c[i][0]=0;
for(i=0;
i++)for(j=0;
j++){
if(x[i]==y[j]){
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1;
}elseif(c[i-1][j]>
=c[i][j-1]){
c[i][j]=c[i-1][j];
b[i][j]=2;
}else{
c[i][j]=c[i][j-1];
b[i][j]=3;
voidLCS(inti,intj,int*x,intb[m][m]){
if(i<
0||j<
0)return;
if(b[i][j]==1){
LCS(i-1,j-1,x,b);
cout<
<
x[i]<
"
"
}elseif(b[i][j]==2)LCS(i-1,j,x,b);
elseLCS(i,j-1,x,b);
voidmain(){
intx[m],y[m],d;
cout<
请输入元素个数"
endl;
cin>
>
d;
请输入元素"
for(inti=0;
cin>
x[i];
y[i]=x[i];
intc[m][m]={0},b[m][m]={0};
QuickSort(x,0,d-1);
LCSLength(x,y,d,c,b);
最长单调递增子序列为:
LCS(d-1,d-1,x,b);
5、会场安排问题:
假设要在足够多的会场里安排一批活动,并希望使用尽可能少的会场。
设计一个有效的贪心算法进行安排。
对于给定的n个待安排的活动,计算使用最少会场的个数。
每个活动i都有一个开始时间和结束时间,分别表示为b(i),f(i)。
iostream>
usingnamespacestd;
#defineM50//最大活动数structActive{
intb;
//开始时间
intf;
//结束时间
intno;
//预安排会场号
}a[M];
//两元素交换位置
voidswap(Active&
a,Active&
b){
Activet=a;
a=b;
b=t;
voidmain(){intk,i,j;
输入待安排活动数:
k;
输入待安排活动的开始时间和结束时间:
//输入活动时间//活动时间排序for(i=1;
=k;
{for(j=i;
j++){if(a[i].b>
a[j].b)swap(a[i],a[j]);
if(a[i].b==a[j].b){if(a[i].f>
a[j].f)swap(a[i],a[j]);
intintsum=1;
//使用的会场数初始化
a[1].no=sum;
for(i=2;
i++){for(n=1;
n<
i;
n++){if(a[n].no!
=0&
a[n].f<
=a[i].b){a[i].no=a[n].no;
a[n].no=0;
//已经安排过的活动就不再比较break;
}
if(n==i)
{
sum+=1;
a[i].no=sum;
}}cout<
输出最少会场数:
\n"
sum<
system("
6、最优分解问题:
设n是一个正整数。
现要求将n分解为若干个互不相同的自然数的和,使得这些自然数的乘积最大。
设计一个算法,得到最优分解方案。
分析:
我们知道如果a+b=常数,贝U|a-b|越小,a*b越大。
贪心策略:
将n分成从2开始的连续自然数的和。
如果最后剩下一个数,将此数在后项优先的方式下均匀地分给前面各项。
voiddicomp(intn,int[]a)
intk=1;
if(n<
3){a[1]=0;
return;
5){a[k]=1;
a[++k]=n-1;
a[1]=2;
n-=2;
while(n>
a[k]){
k++;
a[k]=a[k-1]+1;
n-=a[k];
if(n==a[k]){
a[k]++;
n--;
for(inti=0;
i<
n;
i++)a[k-i]++;
7、子集和问题:
设S{Xi,X2丄,Xn}是n个正整数的集合,c是一个正整数。
那么是否存在S的一个子集S,使得子集中元素之和等于c,即xC。
XS1
intn,c;
inta[100];
intcurrent[100];
//存放当前选择的情况
intbest[100];
//存放最后选择的子集合,best[i]=1,表示包含,反之即不包含。
intd=1;
//判断有无满足的情况
intd2=0;
//是否已经选出子集和
voidBack(intm,intcount);
intmain(){
scanf("
%d%d"
n,&
c);
i++){scanf("
a[i]);
current[i]=best[i]=0;
Back(0,0);
if(d)printf("
nosolution\n"
for(j=0;
j++)//输出满足情况的子集和
if(best[j]==1)printf("
%d\t\t"
a[j]);
voidBack(intm,intcount){
intk;
if(m>
n)return;
if(count==c){d=0;
//有满足的子集和if(d2)return0;
for(k=0;
k<
=m;
k++)best[k]=current[k];
d2=1;
return0;
current[m]=1;
//选入子集和count+=a[m];
Back(m+1,count);
current[m]=0;
//不选入子集和count=count-a[m];
Back(m+1,count);
8设序列Z{Zi,Z2丄,Zk}是序列X{Xi,X2丄,Xm}和丫{%」2丄,yn}的最长公共子序列。
a)请说明最长公共子序列具有最优子结构性质。
b)设C[i][j]记录序列Xi{X1,X2,L,Xi}和Yj{yi,y2,L,yj}的最长公共子序列的长
i度。
由最长公共子序列问题的最优子结构性质建立子问题最优值C[i][j]的递归关系。
C)写出寻找最长公共子序列的算法。
最长公共子序列问题具有最优子结构性质:
Ji门.
1、若Xm=yn,
则Zk=Xm=yn
,且Z[k-1]是X[m-1]和Y[n-1]的最长公共子序列
2、若Xm!
=yn
,且Zk!
=Xm,
则Z是X[m-1]和Y的最长公共子序列
3、若Xm!
=yn,
且Zk!
则Z是Y[n-1]和X的最长公共子序列由性质导出子
问题的递归结构:
当i=0,j=0
时,c[i][j]=0
当i,j>
0Xi=yi
时,c[i][j]=
c[i-1][j-1]+1
0Xi!
=yi
时,c[i][j]
=maX{c[i][j-1],c[i-1][j]}
publicclassLSC{
privateint[][]c,b;
privateintm,n;
privatechar[]A,B;
publicLSC(char[]A,char[]B){
this.A=A;
this.B=B;
m=A.length;
n=B.length;
c=newint[m+1][n+1];
b=newint[m+1][n+1];
n+1;
}for(intj=0;
m+1;
j++){c[j][0]=0;
publicLSC(){}
publicintLSCLength(){for(inti=1;
是相等的话*/
for(intj=1;
j++){/
**如果A[i-1]和E[j-1]if(A[i-1]==B[j-1]){c[i][j]=c[i-1][j-1]+1;
b[i][j]='
0'
/**情况1*/
elseif(c[i-1][j]>
=c[i][j-1]){c[i][j]=c[i-1][j];
1'
/**情况2*/
else{c[i][j]=c[i][j-1];
2'
returnc[m][n];
publicvoidprint(inti,intj){if(i<
=0||j<
=0){return;
}elseif(b[i][j]=='
){
print(i-1,j-1);
System.out.print(A[i-1]);
}elseif(b[i][j]=='
){print(i-1,j);
}else{print(i,j-1);
publicintLSCLength2(inti,intj){if(i<
0){return0;
}else{
if(A[i]==B[j]){
return1+LSCLength2(i-1,j-1);
else{
inta1=LSCLength2(i,j-1);
inta2=LSCLength2(i-1,j);
returna1>
a2?
a1:
a2;
publicstaticvoidmain(String[]args){
char[]A={'
g'
'
f'
d'
a'
s'
c'
};
char[]B={'
t'
LSClsc=newLSC(A,B);
System.out.println(lsc.LSCLength2(7,7));
9、记矩阵连乘积A[i,j]%AiAi1...Aj,ij。
确定计算A[1:
n]的最优计算次序,使得所
需数乘的次数最少。
1、说明矩阵连乘计算次序问题的最优解包含着其子问题的最优解,即最优子结构性质。
2、该问题具备子问题的重叠性质。
3、说明采用动态规划方法可以解决该问题。
4、设计该算法,分析算法的复杂性。
计算A[i:
j]的最优次序所包含的计算矩阵子链A[i:
k]和A[k+1:
j]的次序也是最优的。
设计算A[i:
j],wiwjwn,所需要的最少数乘次数m[i,j],则原问题的最优值为m[1,n]
当i=j时,A[i:
j]=Ai,无需计算,因此,m[i,j]=O,i=1,2,…,n
当i<
j时,利用最优子结构性质计算m[i,j].设A[i:
j]的最优次序在Ak和Ak+1之间断开,则
m:
i,j]=m:
i,k:
+m“+1,门+pi-ipkpj
其中Ai的维数为pi-1xpjk的位置只有j-i种可能,{i,i+1,…,j-1},其中使计算
量最小的那个位置为最优解,数乘次数m[i,j]最小值为问题的最优值可以递归地定义m[i,j]为:
{0i=j}
m[i,j]={min{m[i,k]+m[k+1,j]+pi-1pkpj}i<
j}
将最优值m[ij]对应的断开位置记为s[ij],则可递归的由s[ij]构造出相应的最优解对于1wiwjwn不同的有序对(i,j)对应于不同的子问题。
因此,不同子问题的个数最多只有
由此可见,在递归计算时,许多子问题被重复计算多次。
这也是该问题可用动态规划算法求解的又一显著特征。
用动态规划算法解此问题,可依据其递归式以
自底向上的方式进行计算。
在计算过程中,保存已解决的子问题答案。
每个子
问题只计算一次,而在后面需要时只要简单查一下,从而避免大量的重复计算
最终得到多项式时间的算法matrixchain已经记录了构造最优解所需的全部信
息。
从s[1][n]可知,计算A[1:
n]的最优加括号方式为(A[1:
s[1][n]])
(A[s[1][n]+1:
n])计算A[1:
s[1][n]]的最优加括号方式为(A[1:
s[1][s[1][n]]])(A[s[1][s[1][n]]+1:
10、考虑分数背包问题,定义如下:
给出n个大小为si,s2,…,sn,价值为vi,v2,…,
n
Vn的物品,并设背包容量为C,要找到非负实数X1,X2,…,Xn,使和XiVi在约束
ni1
XisiC下最大。
写出求解问题的贪心算法,估计算法的时间复杂性。
i1
从问题的某一初始解出发;
while能朝给定总目标前进一步do求出可行解的一个解元素;
由所有解元素组合成问题的一个可行解;
从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。
当达到某算法中的某一步不能再继续前进时,算法停止。
#inelude<
#definetotal
10floatp[total],w[total],t[total];
voidgreedy_knaPsack(intX,intc)
{intnote,i;
floatmax;
while
(1){note=0;
max=0;
x;
i++)if((max<
p[i]/w[i])&
(t[i]==0)){max=p[i]/w[i];
note=i;
}if(w[note]<
c)
{t[note]=1;
c-=w[note];
}else{t[note]=c/w[note];
break;
}}}intmain()
{inti=0,n=0;
floatcu;
printf("
请输入物品总数(不大于%d与背包的容
量:
total);
while
(1)
{scanf("
%d%f"
cu);
if(n<
total)break;
elseprintf("
物品总数超出范
围,请重新输入:
}printf("
请输入每个物品的价值与重量:
\n"
%f%f"
p[i],&
w[i]);
t[i]=0;
}greedy_knaPsack(n,cu);
由贪心算法所得最优解是:
i++)printf("
%f"
t[i]);
}时间复杂度分析:
算法
中用到三个for循环,故计算时间复杂度:
O(n)=n+n+n=3n即此算法的时间复杂度为:
O(n)=n