}
5-12
Voidstoogesort(nta[],intleft,intright)
{
if(a[left]>a[right])swap(a,left,right);
if(left+1>=right)return;
intk=(right-left+1)/3;
stoogesort(a,left,right-k);
stoogesort(a,left+k,right);
stoogesort(a,left,right-k);
}
证明:
元素个数n=right-left+1;
(1)若为空表或只有一个元素(n=1时,即left+1==right)时,程序执行if(a[left]>a[right])swap(a,left,right);之后,执行if(left+1>=right)return;即此时程序做了一次元素之间的比较之后,不做任何操作,显然正确.
(2)假设当n=2)时,算确,即对于所有元素个数小于n的元素集,算法能正确排序.
那么,当n=right-left+1时,算法执行程序段:
intk=(right-left+1)/3;
stoogesort(a,left,right-k);
stoogesort(a,left+k,right);
stoogesort(a,left,right-k);
由假设可知:
以上三条语句都能正确运行,所以,当n=right-left+1时,算确.
由以上两点可知,算确.
分析算法的时间复杂度:
排序算法,基本运算仍然是元素之间的比较,所以,算法时间复杂度为:
(用替换或迭代法计算之即可)
6-1设有背包问题实例,n=7,(w0,w1,w2,w3,w4,w5,w6)=(2,3,5,7,1,4,1),(p0,p1,p2,p3,p4,p5,p6)=(10,5,15,7,6,18,3),M=15。
求这一实例的最优解及最大收益.
解:
首先,选择最优量度标准为收益重量比;
其次,依据收益重量比的非增次序对输入(物品)进行排序
(p0/w0,p1/w1,p2/w2,p3/w3,p4/w4,p5/w5,p6/w6)=(5,5/3,3,1,6,4.5,3)
对物品排序结果为:
4,0,5,2,6,1,3
最后,进行贪心选择:
X=(4)X=(4,0)X=(4,0,5)
(剩余载重)U=14U=12U=8
(收益)P=6P=6+10=16P=16+18=34
X=(4,0,5,2)X=(4,0,5,2,6)X=(4,0,5,2,6,1(2/3))
(剩余载重)U=3U=2U=0
(收益)P=34+15=49P=49+3=52P=52+2/3*5=55.33
所以,最优解为x=(1,2/3,1,0,1,1,1);即装入第0,2,4,5,6物品和第1个物品的2/3
最大收益:
P=55.33
6-2,0/1背包问题是一种特殊的背包问题,装入背包的物品不能分割,只允许或者整个物品装入背包,或者不装入,即xi=0,或1,(0<=i为什么?
解:
首先,选择最优量度标准为收益重量比;
其次,依据收益重量比的非增次序对输入(物品)进行排序
(p0/w0,p1/w1,p2/w2,p3/w3,p4/w4,p5/w5,p6/w6)=(5,5/3,3,1,6,4.5,3)
对物品排序结果为:
4,0,5,2,6,1,3
最后,进行贪心选择:
X=(4)X=(4,0)X=(4,0,5)
(剩余载重)U=14U=12U=8
(收益)P=6P=6+10=16P=16+18=34
X=(4,0,5,2)X=(4,0,5,2,6)X=(4,0,5,2,6)
(剩余载重)U=3U=2继续考察第1和第3个
(收益)P=34+15=49P=49+3=52物品,都不能装入.
所以,贪心法求得的0/1背包问题的最优解为x=(1,0,1,0,1,1,1);即装入第0,2,4,5,6物品
最大收益:
P=52
但实际上,当y=(1,1,1,0,1,1,0)即装入第0,1,2,4,5物品,可获收益为P=54,所以,贪心法求得的0/1背包问题的解x一定不是最优解.
原因是:
对于0/1背包问题,贪心法并不能保证使其单位载重下的收益最大,因为通常在背包没还装满时,却再也装不下任何物品,这样,就使得单位载重下的物品收益减少,所以,0/1背包问题通常不能用贪心法求解.
6-3设有带时限的作业排序实例n=7,收益(p0,p1,p2,p3,p4,p5,p6)=(3,5,20,18,1,6,30),作业的时限(d0,d1,d2,d3,d4,d5,d6)=(1,3,4,3,2,1,2),给出以此实例为输入,执行函数JS得到的用最优解和最大收益。
解:
X={5,6,3,2}最大收益为74
函数JS如下:
intJS(int*d,int*x,intn)
{//设p0≥p1≥…≥pn1
intk=0;x[0]=0;
for(intj=1;jintr=k;
while(r>=0&&d[x[r]]>d[j]&&d[x[r]]>r+1)r--;//搜索作业j的插入位置
if((r<0||d[x[r]]<=d[j])&&d[j]>r+1){//若条件不满足,选下一个作业
for(inti=k;i>=r+1;i--)x[i+1]=x[i];//将x[r]以后的作业后移
x[r+1]=j;k++;//将作业j插入r+1处
}
}
returnk;
}
在执行JS函数之前,必须先对输入(即作业)按作业的收益非增次序排序,结果为:
6,2,3,5,1,0,4
X:
接着执行JS函数:
最初,解集合X为空.
6
X:
0123456
首先,考虑作业6,假设将其加入集合X,即x[0]=6;
考虑X中的作业能否均如期完成,因为此时X中只有作业6,其截止时限为2,故,能如期完成,此时,将作业6加入作业子集X中,此时,子集X中的最大可用下标k=0;
X:
6
接着,考虑作业2.
首先搜索作业2在X集合中的插入位置,使得X集合中的元素按作业的截止时限的非减次序排序,因为d6=2,而d2=4,所以,可将作业2插在作业6的后面,即x[1]=2,得到X=(6,2),
X:
6
2
0123456
k
考虑X中的作业能否均如期完成?
因为d6=2>=1,d2=4>=2,所以,X中作业均能如期完成,将作业2加入子集X中.子集X中的最大可用下标k=k+1=1
X:
6
2
考虑作业3.
首先搜索作业3在X集合中的插入位置,使得X集合中的元素按作业的截止时限的非减次序排序,因为d6=2,d2=4,而d3=3所以,可将作业3插在作业6的后面,作业2的前面,得到X=(6,3,2),
X:
6
3
2
考虑X中的作业能否均如期完成?
因为d6=2>=1,d3=3>=2,d2=4>=3所以,X中作业均能如期完成,将作业2加入子集X中.子集X中的最大可用下标k=k+1=2
X:
6
3
2
考虑作业5.
首先搜索作业5在X集合中的插入位置,使得X集合中的元素按作业的截止时限的非减次序排序,因为d6=2,d2=4,d3=3而d5=1所以,可将作业5插在作业6的前面,得到X=(5,6,3,2),
X:
5
6
3
2
考虑X中的作业能否均如期完成?
因为d5=1>=1,d6=2>=2,d3=3>=3,d2=4>=4所以,X中作业均能如期完成,将作业5加入子集X中.子集X中的最大可用下标k=k+1=3
X:
5
6
3
2
考虑作业1.
首先搜索作业1在X集合中的插入位置,使得X集合中的元素按作业的截止时限的非减次序排序,因为d5=1,d6=2,d3=3,d2=4,而d1=3所以,可将作业1插在作业2的前面,作业3的后面,得到X=(5,6,3,1,2),
X:
5
6
3
1
2
考虑X中的作业能否均如期完成?
因为d5=1>=1,d6=2>=2,d3=3>=3,d1=3<4所以,X中1作业不能如期完成,所以,不能将作业1加入子集X.
X:
5
6
3
2
0123456
k
接着考虑作业0,4均不能加入子集X,
故,执行JS得到的最优解为X=(5,6,3,2),最大收益为P=p5+p6+p3+p2=30+20+18+6=74
6-17,最佳装载问题是将一批集装箱装上一艘载重为C的轮船,其中集装箱i的重量为wi(0<=i<=n-1),最优装载问题是指在装载体积不受限制的情况下,求使得装箱数目最多的装载方案.
(1)按贪心策略的要求,给出关于上述最优化问题的形式化描述.
(2)给出贪心法求解这一问题的最优量度标准;
(3)讨论其最优解的最优子结构.
(4)编写装箱问题的贪心算法;
(5)设有重量为(4,6,3,5,7,2,9)的7个集装箱,轮船载重为26,求最优解.
解;
(1),形式化描述如下:
给定C>0,wi>0
求X=(
)使得
并且使
最大
(2)以重量作为最优量度标准,以重量最轻者先装来选择集装箱装上船
(3)设(x0,x1,----xn-1)是最优装载问题的最优解,则易知(x1,x2,----xn-1)是轮船载重为C-x0w0且待装船的集装箱为{1,3----n-1}时相应最优装载问题的一个最优解,即最优装载问题具有最优子结构特性。
否则,假设(x1,x2,----xn-1)不是子问题的最优解,假设有另一个解Z=(z1,z2,----zn-1)是子问题的最优解,则有:
则:
且
,即(x0,z1,z2,--zn-1)是最优装载问题的最优解,与(x0,x1,----xn-1)是最优装载问题的最优解矛盾,所以,(x1,x2,----xn-1)是子问题的最优解,故最优装载问题具有最优子结构特性。
(4)参考程序1
/*箱子信息结构体*/
structgoodinfo
{
floatw;/*箱子重量*/
intX;/*箱子存放的状态*/
intflag;/*箱子编号*/
};
/*按物品重量做升序排列*/
voidsort(goodinfogoods[],intn)
{
intj,i;
for(j=2;j<=n;j++)
{
goods[0]=goods[j];
i=j-1;
while(goods[0].w{
goods[i+1]=goods[i];
i--;
}
goods[i+1]=goods[0];
}
}
/*用贪心法对物品进行选择装入*/
voidloading(goodinfogoods[],floatM,intn)
{
floatcu;
inti,j;
intA=0;/*对装入箱子进行计数*/
for(i=1;i<=n;i++)/*赋初值*/
goods[i].X=0;
cu=M;/*船的剩余载重*/
for(i=1;i{
if(goods[i].w>cu)/*当该箱重量大于剩余载重跳出*/
break;
goods[i].X=1;
A++;
cu=cu-goods[i].w;/*确定船的剩余载重*/
}
for(j=2;j<=n;j++)/*对箱子按序号大小作升序排列*/
{
goods[0]=goods[j];
i=j-1;
while(goods[0].flag{
goods[i+1]=goods[i];
i--;
}
goods[i+1]=goods[0];
}
cout<<"①最优解为:
"<for(i=1;i<=n;i++)
{
cout<<"第"<
";
cout<}
cout<<"<0:
未装入;1:
装入>"<cout<cout<<"②最多能装入的箱子数为:
";
cout<}
(5)
首先,选择最优量度标准为重量;
其次,依据集装箱重量的非减次序对输入(物品)进行排序
对集装箱的排序结果为:
5,2,0,3,1,4,6
最后,进行贪心选择:
X=(5)X=(5,2)X=(5,2,0)
(剩余载重)U=24U=21U=17
X=(5,2,0,3)X=(5,2,0,3,1)X=(5,2,0,3,1)
(剩余载重)U=12U=6
所以,最优解为X=(0,1,2,3,5),最优解值为5
参考程序2
•publicstaticfloatloading(floatc,float[]w,int[]x)
•{
•intn=w.length;
•Element[]d=newElement[n];
•for(inti=0;i•d[i]=newElement(w[i],i);
•MergeSort.mergeSort(d);
•floatopt=0;
•for(inti=0;i•for(inti=0;i•x[d[i].i]=1;
•opt+=d[i].w;
•c-=d[i].w;
•}
•returnopt;
}
7-5设有4个矩阵连乘积ABCD:
A:
45*8,B:
8*40,C:
40*25,D:
25*10,,请求出它们的最优计算次序和计算量。
解:
p0=45,p1=8,p2=40,p3=25,p4=10
可只给出矩阵形式
计算m矩阵为:
m[0][1]=p0*p1*p2=45*8*40=14400;
m[1][2]=p1*p2*p3=8*40*25=8000;
m[2][3]=p2*p3*p4=40*25*10=11250;
m[0][2]=m[0][0]+m[1][2]+p0*p1*p3=8000+45*8*25=8000+9000=17000
=m[0][1]+m[2][2]+p0*p2*p3=14400+45*40*25=14400+45000
m[1][3]=m[1][1]+m[2][3]+p1*p2*p4=11250+8*40*10