}
运行结果为:
3.设X[0:
n-1]和Y[0:
n-1]为两个数组,每个数组中含有n个已排好序的数。
试设计一个
时间算法,找出
和
的2n个数的中位数。
(分治法)
a、基本思想:
解决问题的核心:
找出将大问题分割成较小规模的相同问题的切割点,并递归定义大问题与子问题之间的关系。
确定切割点:
对于两个数组,我们可以从他们中分别选取出一个中位数,称为x,y,并将两个数组的左右边界称之为aLeft,aRight,bLeft,bRight。
对比两个中位数,如果X数组中的中位数大于Y数组中的中位数,且X数组中的元素个数为偶数个,则X数组被切割为X[aLeft,x-1],Y被切割为Y[y,bRight],如果X数组的元素个数不为偶数个的话,则直接将X切割为X[aLeft,x]。
如果X数组的中位数小于Y数组的中位数,取值情况刚好相反。
递归关系:
根据上面所述,对于原问题X[aLeft,aRight],Y[bLeft,bRight]。
假设切割后的子问题为X[aLeft,x-1],Y[y,bRight]。
则求解X[aLeft,aRight],Y[bLeft,bRight]问题的中位数,归结于求解子问题X[aLeft,x-1],Y[y,bRight]的中位数。
递归结束条件:
当切割后得到的子问题的两个数组的长度都为1位时,整个递归结束。
b、复杂度分析:
因为数组比较的范围每次缩小一半,所以有递推公式为:
T(n)=1n=1
T(n)=T(n/2)+1n>1
易算出时间复杂度为
c、代码实现
#include
usingnamespace:
:
std;
#defined10
intmedian(intx[],inty[],intxLeft,intxRight,intyLeft,intyRight){
if(xLeft==xRight)
{
return(x[xLeft]+y[yLeft])/2;
}
intxm=(xLeft+xRight)/2;
intym=(yLeft+yRight)/2;
if((xLeft+xRight)%2==0)
{//为奇数
if(x[xm]{
median(x,y,xm,xRight,yLeft,ym);
}
else
{
median(x,y,xLeft,xm,ym,yRight);
}
}
else
{//为偶数
if(x[xm]{
median(x,y,xm+1,xRight,yLeft,ym);
}
else
{
median(x,y,xLeft,xm,ym+1,yRight);
}
}
}
intmain()
{
intm;inta[d],b[d];
cout<<"Enterdimensionm:
"<cin>>m;
cout<<"Enterarraya:
"<for(inti=0;icin>>a[i];
cout<<"Enterarrayb:
"<for(intj=0;jcin>>b[j];
intmid=median(a,b,0,m-1,0,m-1);
cout<<"Themedianis:
"<return0;
}
运行结果为:
4.设计一个O(n*n)时间的算法,找出由n个数组成的序列最长单调递增子序列.P87页(参考P56页)(动态规划算法)
a、算法思路:
序列X按非递减顺序排列,形成新序列Y,问题就转变成求解X和Y的LCS。
b、时间复杂度:
使用快速排序,则排序过程的时间复杂度为O(nlgn),而求两个序列的LCS的时间复杂度为O(n^2)(因为X、Y长度相等),综合可知该解法的时间复杂度为O(n^2)。
c、代码实现
#include
#definem10
//快速排序
voidQuickSort(intR[],ints,intt)
{
inti=s,j=t;
inttmp;
if(s{
tmp=R[s];
while(i!
=j)
{
while(j>i&&R[j]>=tmp)
j--;
R[i]=R[j];
while(ii++;
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{
c[0][i]=0;
c[i][0]=0;
}
for(i=0;ifor(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<}
elseif(b[i][j]==2)
LCS(i-1,j,x,b);
else
LCS(i,j-1,x,b);
}
voidmain()
{
intx[m],y[m],d;
cout<<"请输入元素个数"<cin>>d;
cout<<"请输入元素"<for(inti=0;i{
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);
cout<<"最长单调递增子序列为:
"<LCS(d-1,d-1,x,b);
}
结果为:
7.礼物分配问题.两兄弟Alan和Bob,共同分配n个礼物.每个礼物只能分给其中的一个人,且不能分成两个.每个礼物i的价值为vi,为正整数.设a和b分别表示Alan和Bob所收到的礼物的总价值,V=
为所有礼物的总价值.为使两兄弟高兴,我们希望尽可能地均分这些礼物,即|a-b|打到最小
试设计-O(n*V)时间的动态规划算法,使得|a-b|达到最小,并求出礼物的分割集合
(P77页)(动态规划算法)
8.(4.7)多处最优服务问题P131页(贪婪算法)(与十人打水的问题一样)