最小距离点对的暴力枚举算法与分治算法
最小距离点对问题,顾名思义,即在一堆点中,寻找最小距离的点对。
暴力枚举的时间复杂度为O(n2),分治算法的时间复杂度为O(nlogn)。
以下解决的问题是:
生成任意多个随机点,找到最近的点对后,将这对点排除在外,继续寻找剩下的点的最近的点对,重复上述操作,直到把所有点排除完毕(个数剩下为1,也停止操作)。其中,输出两种算法的执行时间,暴力枚举法用白线连接,分治算法用红线连接,用白线来验证红线的结果是否正确。
视频:https://zhuanlan.zhihu.com/p/711430070
/// <summary>
/// Find Closest Point Pair Using Divide and Conqure Method, time complex is O(nlogn).
/// </summary>
/// <param name="pts"></param>
/// <returns></returns>
public static DbPt[] ClosestPtPair(List<DbPt> pts)
{
//移除重复点
GMath.DelSamePt(pts);
//基本条件
if (pts.Count <= 3)
{
return ClosestPtPairBruteForce(pts);
}
List<DbPt> ptsX = (from n in pts
select n.EleCopy()).OrderBy(p => p.X).ThenBy(p=>p.Y).ToList();
//List<DbPt> ptsY = (from n in pts
// select n.EleCopy()).OrderBy(p => p.Y).ToList();
//return ClosestPtPair(ptsX, ptsY);
return ClosestPtPairTemp(ptsX);
}
static DbPt[] ClosestPtPairTemp(List<DbPt> ptsX)
{
//DbPt[] nearestL=null, //最近左点对
// nearestR = null,//最近右点对
// nearestSplit=null;//最近分离点对
if (ptsX.Count <= 3)
{
return ClosestPtPairBruteForce(ptsX);
}
else
{
int mid = ptsX.Count / 2;
List<DbPt> Lx = ptsX.Take(mid).ToList();
//List<DbPt> Ly = (from n in Lx select n).OrderBy(p=>p.Y).ToList();
List<DbPt> Rx = ptsX.Skip(mid).Take(ptsX.Count - mid).ToList();
//List<DbPt> Ry = (from n in Rx select n).OrderBy(p=>p.Y).ToList();
DbPt[] nearestL = ClosestPtPairTemp(Lx);
DbPt[] nearestR = ClosestPtPairTemp(Rx);
double delta = Math.Min(
GMath.Distance(nearestL[0], nearestL[1]),
GMath.Distance(nearestR[0], nearestR[1])
) ;
DbPt[] nearestSplit = ClosestSplitPair(ptsX,delta);
List<DbPt[]> candidates = new List<DbPt[]>
{
nearestL,nearestR
};
if (nearestSplit != null)
{
candidates.Add(nearestSplit);
}
candidates.Sort((a, b) => GMath.Distance(a[0], a[1]).CompareTo(GMath.Distance(b[0], b[1])));
return candidates[0];
}
}
static DbPt[] ClosestSplitPair(List<DbPt> ptsX,double delta,double allow=0.01)
{
int mid = ptsX.Count / 2;
double xMid = ptsX[mid].X;
List<DbPt> Sy = (from n in ptsX
where n.X <= xMid + delta && n.X >= xMid - delta
select n).OrderBy(p=>p.Y).ToList();
double best = delta;
DbPt[] result = null;
for(int i = 0; i < Sy.Count; i++)
{
for(int j = 1; j < Math.Min(7, Sy.Count - i); j++)
{
if (GMath.Distance(Sy[i], Sy[i + j]) < best)
{
best = GMath.Distance(Sy[i], Sy[i+j]);
result = new DbPt[]
{
Sy[i],Sy[i+j]
};
}
}
}
return result;
}
/// <summary>
/// Find Closest Point Pair Using Brue Force Method
/// </summary>
/// <param name="pts"></param>
/// <returns></returns>
public static DbPt[] ClosestPtPairBruteForce(List<DbPt> pts)
{
List<Tuple<DbPt, DbPt>> ptsPair = new List<Tuple<DbPt, DbPt>>();
for (int i = 0; i < pts.Count; i++)
{
for (int j = i + 1; j < pts.Count; j++)
{
ptsPair.Add(Tuple.Create(pts[i], pts[j]));
}
}
var tup = ptsPair.OrderBy(t => GMath.Distance(t.Item1, t.Item2)).FirstOrDefault();
if (tup != null)
{
return new DbPt[] { tup.Item1, tup.Item2 };
}
return null;
}
#####
愿你一寸一寸地攻城略地,一点一点地焕然一新
#####