中科大算法实验4求平面最近点对算法.docx
- 文档编号:6335287
- 上传时间:2023-01-05
- 格式:DOCX
- 页数:13
- 大小:533.69KB
中科大算法实验4求平面最近点对算法.docx
《中科大算法实验4求平面最近点对算法.docx》由会员分享,可在线阅读,更多相关《中科大算法实验4求平面最近点对算法.docx(13页珍藏版)》请在冰豆网上搜索。
中科大算法实验4求平面最近点对算法
《算法设计与分析》上机报告
姓名:
张先荣
学号:
SA16225439
日期:
2016/11/22
上机题目:
4th:
求最近点对算法
实验环境:
CPU;I3;内存:
8G;操作系统Windows7;软件平台:
Visualstudio2013;
一、算法设计与分析:
题目一:
给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。
我们考虑将所给的平面上n个点的集合S分成2个子集S1和S2,每个子集中约有n/2个点,?
然后在每个子集中递归地求其最接近的点对。
在这里,一个关键的问题是如何实现分治法中的合并步骤,即由S1和S2的最接近点对,如何求得原集合S中的最接近点对,因为S1和S2的最接近点对未必就是S的最接近点对。
如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决。
但是,如果这2个点分别在S1和S2中,则对于S1中任一点p,S2中最多只有n/2个点与它构成最接近点对的候选者,仍需做n2/4次计算和比较才能确定S的最接近点对。
因此,依此思路,合并步骤耗时为O(n2)。
整个算法所需计算时间T(n)应满足:
T(n)=2T(n/2)+O(n2)
在一维的情形,距分割点距离为δ的2个区间(m-δ,m](m,m+δ]中最多各有S中一个点。
因而这2点成为唯一的末检查过的最接近点对候选者。
二维的情形则要复杂些,此时,P1中所有点与P2中所有点构成的点对均为最接近点对的候选者。
在最坏情况下有n2/4对这样的候选者。
但是P1和P2中的点具有以下的稀疏性质,它使我们不必检查所有这n2/4对候选者。
考虑P1中任意一点p,它若与P2中的点q构成最接近点对的候选者,则必有d(p,q)<δ。
满足这个条件的P2中的点有多少个呢?
容易看出这样的点一定落在一个δ×2δ的矩形R中.
因此d(u,v)≤5δ/6<δ。
这与δ的意义相矛盾。
也就是说矩形R中最多只有6个S中的点。
图4(b)是矩形R中含有S中的6个点的极端情形。
由于这种稀疏性质,对于P1中任一点p,P2中最多只有6个点与它构成最接近点对的候选者。
因此,在分治法的合并步骤中,我们最多只需要检查6×n/2=3n对候选者,而不是n2/4对候选者。
这是否就意味着我们可以在O(n)时间内完成分治法的合并步骤呢?
现在还不能作出这个结论,因为我们只知道对于P1中每个S1中的点p最多只需要检查P2中的6个点(确切的说,是矩形R中的6个S中的点),但是我们并不确切地知道要如何检查。
为了解决这个问题,我们可以将p和P2中所有S2的点投影到垂直线l上。
由于能与p点一起构成最接近点对候选者的S2中点一定在矩形R中,并且要满足d(p,q)<δq∈P2,因此满足条件的点它们在直线l上的投影点距p在l上投影点的距离小于δ,由上面的分析可知,这种投影点不多于6个。
因此,若将P1和P2中所有S的点按其y坐标排好序,则对P1中所有点p,对排好序的点列作一次扫描,就可以找出所有最接近点对的候选者,对P1中每一点最多只要检查P2中排好序的相继6个点。
至此,我们可以给出用分治法求二维最接近点对的算法CPAIR2如下:
functionCPAIR2(S);
begin
if|S|=2
thenδ:
=S中这2点的距离
elseif|S|=0
thenδ:
=∞
else
begin
1.m:
=S中各点x坐标值的中位数;构造S1和S2,使S1={p∈S|px≤m}和S2={p∈S|px>m}
2.δ1:
=CPAIR2(S1);δ2:
=CPAIR2(S2);
3.δm:
=min(δ1,δ2);
4.设P1是S1中距垂直分割线l的距离在δm之内的所有点组成的集合,P2是S2中距分割线l的距离在δm之内所有点组成的集合。
将P1和P2中的点依其y坐标值从小到大排序,并设P1*和P2*是相应的已排好序的点列;
5.通过扫描P1*以及对于P1*中每个点检查P2*中与其距离在δm之内的所有点(最多6个)可以完成合并。
当P1*中的扫描指针逐次向上移动时,P2*中的扫描指针可在宽为2δm的一个区间内移动。
设δl是按这种扫描方式找到的点对间的最小距离;
6.δ=min(δm,δl);
end;
return(δ);
end;
下面我们来分析一下算法CPAIR2的计算复杂性。
设对于n个点的平面点集S,算法耗时T(n)。
算法的第1步和第5步用了O(n)时间,第3步和第6步用了常数时间,第2步用了2T(n/2)时间。
若在每次执行第4步时进行排序,则在最坏情况下第4步要用O(nlogn)时间。
这不符合我们的要求。
因此,在这里我们要作一个技术上的处理。
我们采用设计算法时常用的预排序技术,即在使用分治法之前,预先将S中n个点依其y坐标值排好序,设排好序的点列为P*。
在执行分治法的第4步时,只要对P*作一次线性扫描,即可抽取出我们所需要的排好序的点列P1*和P2*。
然后,在第5步中再对P1*作一次线性扫描,即可求得δl。
因此,第4步和第5步的两遍扫描合在一起只要用O(n)时间。
这样一来,经过预排序处理后的算法CPAIR2所需的计算时间T(n)满足递归方程:
显而易见T(n)=O(nlogn),预排序所需的计算时间为O(n1ogn)。
因此,整个算法所需的计算时间为O(nlogn)。
在渐近的意义下,此算法已是最优的了。
二、核心代码:
题目一:
1.生成随机数:
如图,使用C#代码,先生成坐标的随机数:
2.生成的随机数之后,将这些点以中位数分治:
Closetpair是递归函数。
3.求中位数的最进点对,将这些点对放到新的数组中:
4.将这些最近点对按y坐标排序:
由于C#库函数只能对数组排序,不得不将对象数组取出来,拍完序之后再放回去:
5.每个点与附近7个点进行比较:
三、结果与分析:
题目一:
1.输出15,随机生成15个坐标对:
2.输入155,随机生成坐标对:
随机生成15万个:
分析:
如果在递归调用时,不对Y排序,非常卡,运行15万个坐标至少要运行5分钟。
。
所以,主函数要对X排序,递归时要对Y排序。
四、备注
总结:
本实验重点:
(1)主函数对X排序,递归时对Y排序。
(2)筛选的中位数附近的点,对每个点取六个比较即可。
(3)如图:
附录(源代码)
算法源代码(C/C++/JAVA描述)C#:
publicpartialclassForm1:
Form
{
publicForm1()
{
InitializeComponent();
}
publicclassPoint
{
publicfloatx,y;
}
publicstaticfloatNo_distance=1000000;
publicstaticfloatAAA,BBB,CCC,DDD;
publicstaticvoidSetPoints(Point[]points,intlength)
{
Randomra=newRandom();
for(inti=0;i { points[i]=newPoint(); points[i].x=(float)ra.NextDouble()*200-100; points[i].y=(float)ra.NextDouble()*200-100; } } publicstaticfloatDistance(Pointa,Pointb) { return(float)Math.Sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } publicstaticfloatClosetspair(Point[]points,intlength,Pointa,Pointb) { floatdistance;//记录集合中最近的两点 floatd1,d2;//记录分割后两个子集中各自最小点对距离 inti=0,j=0,k=0;//用于控制for循环的循环变量 Pointa1=newPoint(); Pointb1=newPoint(); Pointa2=newPoint(); Pointb2=newPoint(); //保存分割后两个子集中最小点对 if(length<2)returnNo_distance;//如果子集长度小于2,定义为最大距离,表示不可达 if(length==2) { distance=Distance(points[0],points[1]); } else { Point[]pts1=newPoint[length];//两个子集分别放入这两个 Point[]pts2=newPoint[length]; floatmid=points[(length-1)/2].x;//排完序后的中间下标值,即中位数 for(i=0;i { pts1[i]=points[i]; } for(j=0,i=length/2;i { pts2[j++]=points[i]; } d1=Closetspair(pts1,length/2,a1,b1); d2=Closetspair(pts2,length-length/2,a2,b2); if(d1 else{distance=d2;a=a2;b=b2;} //求解跨分割线,并在6*26区间内最近的点对 Point[]pts3=newPoint[length]; for(i=0,k=0;i if(Math.Abs(points[i].x-mid)<=distance)pts3[k++]=points[i]; float[]array=newfloat[k]; for(intiii=0;iii { array[iii]=pts3[iii].x; } Array.Sort(array); for(intia=0;ia { pts3[ia].x=array[ia]; } for(i=0;i for(j=i+1;j<=i+7&&j { if(Distance(pts3[i],pts3[j]) {//如果跨分割线的两点距离小于已知最小距离,则记录该距离 distance=Distance(pts3[i],pts3[j]); a=pts3[i]; b=pts3[j]; AAA=a.x; BBB=a.y; CCC=b.x; DDD=b.y; } } } returndistance; } privatevoidbutton1_Click(objectsender,EventArgse) { intN;//随机生成的点对个数。 Pointa=newPoint(); Pointb=newPoint(); floatdistence; if(textBox2.Text=="") { MessageBox.Show("请您先输入需要随机生成的多少对? ","你好! 输入为空",MessageBoxButtons.OKCancel); } else{ N=Int32.Parse(textBox2.Text.Trim()); if(N<2) { MessageBox.Show("请输入大于等于2的点个数! ! "); } Point[]points=newPoint[N]; SetPoints(points,N); for(inti=0;i { listBox1.Items.Add("("+points[i].x+","+points[i].y+")"); } float[]array=newfloat[N]; for(intiii=0;iii { array[iii]=points[iii].x; } Array.Sort(array); for(intia=0;ia { points[ia].x=array[ia]; } for(inti=0;i { listBox2.Items.Add("("+points[i].x+","+points[i].y+")"); } distence=Closetspair(points,N,a,b); textBox1.Text="最近点对为: "+"("+AAA+","+BBB+")和"+"("+CCC+","+DDD+")"; textBox3.Text="最近点对距离为: "+distence; } } } }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 中科大 算法 实验 平面 最近
![提示](https://static.bdocx.com/images/bang_tan.gif)