中南大学算法实验报告.docx

上传人:b****6 文档编号:8118080 上传时间:2023-01-28 格式:DOCX 页数:11 大小:182.58KB
下载 相关 举报
中南大学算法实验报告.docx_第1页
第1页 / 共11页
中南大学算法实验报告.docx_第2页
第2页 / 共11页
中南大学算法实验报告.docx_第3页
第3页 / 共11页
中南大学算法实验报告.docx_第4页
第4页 / 共11页
中南大学算法实验报告.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

中南大学算法实验报告.docx

《中南大学算法实验报告.docx》由会员分享,可在线阅读,更多相关《中南大学算法实验报告.docx(11页珍藏版)》请在冰豆网上搜索。

中南大学算法实验报告.docx

中南大学算法实验报告

算法分析与设计

实验报告

 

学院:

 信息科学与工程学院

专业班级:

 igot7

指导老师:

   

学号:

  igot7

姓名:

   鸟宝宝

a.合并排序

合并排序是分治法的应用,把需要排序的数组A[1-n],一分为二A[1-n/2]和A[n/2+1-n],然后在对每一个子数组递归排序,接着再把这两个子数组合并成一个有序的数组。

算法描述:

第一步:

申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

第二步:

设定两个指针,最初位置分别为两个已经排序序列的起始位置

第三步:

比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

重复步骤3直到某一指针超出序列尾,将另一序列剩下的所有元素直接复制到合并序列尾

关键代码:

privatestaticvoidSort(int[]a,intleft,intright){

if(left>=right)

return;

intmid=(left+right)/2;

Sort(a,left,mid);

Sort(a,mid+1,right);

merge(a,left,mid,right);

}

privatestaticvoidmerge(int[]a,intleft,intmid,intright){

int[]tmp=newint[a.length];

intr1=mid+1;

inttIndex=left;

intcIndex=left;

//逐个归并

while(left<=mid&&r1<=right){

if(a[left]<=a[r1])

tmp[tIndex++]=a[left++];

else

tmp[tIndex++]=a[r1++];

}

//将左边剩余的归并

while(left<=mid){

tmp[tIndex++]=a[left++];

}

//将右边剩余的归并

while(r1<=right){

tmp[tIndex++]=a[r1++];

}

System.out.print("第"+(++number)+"次排序:

");

//从临时数组拷贝到原数组

while(cIndex<=right){

a[cIndex]=tmp[cIndex];

//输出中间归并排序结果

System.out.print(a[cIndex]+"");

cIndex++;

}

System.out.println();

}

运行结果截屏:

算法分析:

合并排序满足分治法的基本公式

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

其中2T(n/2)是2个子问题求解,即对两个子数组排序;

而f(n)是将子问题合起来求原始问题的解的代价,即将两个有序的子数组合并为一个有序的数组。

在最终的合并阶段,键值的比较的代价,在最坏的情况下是n-1,(比如每个数组的第i号轮流被放入数组),根据主定理,T(n)=O(nlogn)。

 

b.0-1背包问题

问题描述:

在0/1背包问题中,需对容量为W的背包进行装载。

从n个物品中选取装入背包的物品,每件物品j的重量为wj,价值为vi。

对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高。

有3中方法可解:

动态规划法:

递推式:

K(w,j)=max{K(w-wj,j-1)+vj,K(w,j-1)}w≥wj

K(w,j)=K(w,j-1)w

初始条件:

K(0,j)=0,K(w,0)=0.

初始化条件表示把前面i个物品装入容量为0的背包和把0个物品装入容量为j的背包,得到的价值均为0。

第二个式子说明:

如果第i个物品的重量大于背包的容量,则装入第i个物品得到的最大价值和装入第i-1个物品得到的最大价值是相同的,即物品i不能装入背包中。

第一个式子说明:

如果第i个物品的重量小于背包的容量,则会有两种情况:

(1)如果把第i个物品装入背包,则背包中物品的价值就等于把前i-1个物品装入容量为iwj的背包中的价值加上第i个物品的价值iv;

(2)如果第i个物品没有装入背包,则背包中物品的价值就是等于把前i-1个物品装入容量为j的背包中所取得的价值。

显然,取二者中价值较大者作为把前i个物品装入容量为j的背包中的最优解。

w-wj

 w

 W

j-1 

K[w-wj, j-1]

+vj

K[w,j-1]

j

K[w, j]

n

目标

构建的表格:

 

时间复杂度为:

O(nw)

分支限界法:

1.按单位价值对待处理的物品进行排序

2.计算可行结点可获得的最大价值的上界

boundfunction(上界函数):

ub=v+(W-w)(vi+1/wi+1)

3.用结点的上界值作为优先级,建立优先队列

4.按照优先队列对解空间进行搜索

回溯法:

回溯法应用深度优先遍历解空间,如果按单位价值排序可以剪掉部分右边的枝,如果设置约束条件可以剪掉不是最优解的枝。

在搜索解空间树时,只要其左儿子结点是一个可行结点,搜索就进入其左子树。

当右子树有可能包含最优解时才进入右子树搜索。

否则将右子树剪去。

设r是当前剩余物品价值总和;cp是当前价值;bestp是当前最优价值。

当cp+r≤bestp时,可剪去右子树。

计算右子树中解的上界的更好方法是将剩余物品依其单位重量价值排序,然后依次装入物品,直至装不下时,再装入该物品的一部分而装满背包。

由此得到的价值是右子树中解的上界。

确定了解空间的组织结构后,回溯法就从开始结点(根结点)出发,以深度优先的方式搜索整个解空间。

这个开始结点就成为一个活结点,同时也成为当前的扩展结点。

在当前的扩展结点处,搜索向纵深方向移至一个新结点。

这个新结点就成为一个新的活结点,并成为当前扩展结点。

如果在当前的扩展结点处不能再向纵深方向移动,则当前扩展结点就成为死结点。

此时,应往回溯至最近的一个活结点处,并使这个活结点成为当前的扩展结点。

回溯法即以这种工作方式递归地在解空间中搜索,直至找到所要求的所有解或解空间中已没有活结点时为止。

贪心法:

贪心法是“步步贪心”,从局部最优推进得到全局最优的近似解,所以用贪心法存在问题:

1).不能保证求得的最后解是最佳的;

2).不能用来求最大或最小解问题;

3).只能求满足某些约束条件的可行解的范围。

目标是价值最大

约束条件是装入的物品总重量不超过背包容量:

∑wi<=M(M=150)

(1)根据贪心的策略,每次挑选价值最大的物品或者所占空间最小的物品装入背包,似乎不行

(2)每次选取单位容量价值最大的物品,成为解题的策略。

关键代码:

publicvoidgetMaxValue(){

PriorityQueuepq=newPriorityQueue();//根节点

thingNodeinitial=newthingNode();

initial.level=-1;

initial.upprofit=26;

pq.add(initial);

while(!

pq.isEmpty()){

thingNodefatherNode=pq.poll();//叶子节点

if(fatherNode.level==n-1){

if(fatherNode.value>maxValue){

maxValue=(int)fatherNode.value;

for(inti=n-1;i>=0;i--){

bestWay[i]=fatherNode.Left;

fatherNode=fatherNode.father;

}

}

}

else{//判断是否加入队列

if(weight[fatherNode.level+1]+fatherNode.weight<=capacity){

thingNodenewNode=newthingNode();

newNode.level=fatherNode.level+1;

newNode.value=fatherNode.value+value[fatherNode.level+1];

newNode.weight=weight[fatherNode.level+1]+fatherNode.weight;

newNode.upprofit=Bound(newNode);

newNode.father=fatherNode;

newNode.Left=1;

if(newNode.upprofit>maxValue)

pq.add(newNode);}

//向右节点搜索,其能够取到的价值上界通过父亲节点的上界减去本层物品的价值。

if((fatherNode.upprofit-value[fatherNode.level+1])>maxValue){

thingNodenewNode2=newthingNode();

newNode2.level=fatherNode.level+1;

newNode2.value=fatherNode.value;

newNode2.weight=fatherNode.weight;

newNode2.father=fatherNode;

newNode2.upprofit=fatherNode.upprofit-value[fatherNode.level+1];

newNode2.Left=0;

pq.add(newNode2);

}

}

}

//用于计算该节点的最高价值上界

publicdoubleBound(thingNodeno){

doublemaxLeft=no.value;

intleftWeight=capacity-no.weight;

inttemplevel=no.level;//尽力依照单位重量价值次序装剩余的物品

while(templevel<=n-1&&leftWeight>weight[templevel]){

leftWeight-=weight[templevel];

maxLeft+=value[templevel];

templevel++;}//不能装时,用下一个物品的单位重量价值折算到剩余空间。

if(templevel<=n-1){

maxLeft+=value[templevel]/weight[templevel]*leftWeight;}

returnmaxLeft;}

运行结果截屏

输入:

intn=9;

intcapacity=36;

int[]weight={6,3,4,2,5,7,9,10,13};

double[]value={30,14,16,9,20,18,34,45,27};

输出:

 

c.N皇后问题

问题描述:

n皇后问题等于于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。

即规定每一列放一个皇后,不会造成列上的冲突;当第i行被某个皇后占领后,则同一行上的所有空格都不能再放皇后,要把以i为下标的标记置为被占领状态。

算法设计:

首先想到的就是把棋盘存储为一个二维数组,然后在需要在第i行第j列放置皇后时,根据问题的描述,首先判断是在第i行是否有皇后,然后判断第j列是否有皇后,最后需要判断在同一斜线上是有皇后,按照该方法需要判断两次,正对角线方向和负对角线方向。

后来发现可以把棋盘存储为一个N维数组a[N],数组中第i个元素的值代表第i行的皇后位置,方便将问题的空间规模压缩为一维O(N)。

在判断是否冲突时,首先每行只有一个皇后,在数组中只占据一个元素的位置,行冲突就不存在了,其次是列冲突,判断一下是否有a[i]与当前要放置皇后的列j相等即可。

至于斜线冲突,通过观察可以发现所有在斜线上冲突的皇后的位置都有规律即它们所在的行列互减的绝对值相等。

这样某个位置是否可以放置皇后的问题就解决了。

n皇后问题是回溯法的经典应用,所以使用回溯法来解决该问题。

具体实现也有两个途径,递归和非递归。

递归方法大致如下:

voidqueen(inti)

{

if(n==i)//如果已经找到结果,则打印结果

print_result();

else{

for(k=0toN){//第i行每一个列

if(can_place(i,k){

place(i,k);//放置皇后

queen(i+1);}

}

}

}

非递归方法的一个关键何时回溯及如何回溯的问题。

程序首先对N行中的每一行进行搜索,寻找可以放置皇后的位置,具体方法是对该行的每一列进行搜索,看是否可以放置皇后,如果可以,则在该列放置一个皇后,然后继续搜索下一行的皇后位置。

如果已经搜索完所有的列都没有找到可以放置皇后的列,此时就应该回溯到上一层,把上一行皇后的位置往后移,如果上一行皇后移动后也找不到位置,则继续回溯直至某一行找到皇后的位置或回溯到第一行,如果第一行皇后也无法找到可以放置皇后的位置,则说明已经找到所有的解程序终止。

如果该行已经是最后一行,则搜索完该行后,如果找到放置皇后的位置,则说明找到一个结果,打印出来。

如果我们要找的是所有N皇后问题所有的解,那么此时并不能再此处结束程序。

此时应该清除该行的皇后,从当前放置皇后列数的下一列继续搜索。

部分代码:

publicvoidcalc(){sp=0;

stack[sp++]=newQueen();

while(sp>=0&&sp<=num-1){

Queenqueen=getQueen(sp);

if(null==queen){

booleanflag=true;

while(flag){

--sp;

if(sp<0)break;

if(stack[sp].pos.y==num-1){

}

else{

stack[sp++].pos.y++;

flag=false;

for(intk=0;k

if(stack[k].isUnderControl(stack[sp-1].pos)){

flag=true;

break;

}

}

}

}

}

else{

stack[sp++]=queen;

}

}

}

publicQueengetQueen(intx){

booleanflag=true;

inty=0;

while(flag){flag=false;

for(inti=0;i

if(stack[i].isUnderControl(newPoint(x,y)))

{flag=true;break;}

}

if(flag&&y<=num-1){y++;}

elseif(y>=num){returnnull;}}

returnnewQueen(newPoint(x,y));

}

判定是否冲突

publicbooleanisUnderControl(Pointpoint){

booleanret=true;

if(point.x!

=pos.x&&point.y!

=pos.y&&Math.abs(point.x-pos.x)!

=Math.abs(point.y-pos.y)&&Math.abs(point.x+point.y)!

=Math.abs(pos.x+pos.y))

{ret=false;}

returnret;

}

运行结果截屏:

输入n=10

输入n=20

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 工学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1