礼品包装算法 java(gift wrapping)
convexHull(参考的博客)
这个题有很多解法,我采用的是gift wrapping算法.
思路:
1.找一个极点(左上角,左下角,右上角或者右下角,我找得是左上角)
2.遍历所有点,找出和极点偏转角度最小的(顺时针).
3.将当前点作为下一个极点,继续找点.
4.直到找到第一个极点,算法结束.
public static Set<Point> convexHull(Set<Point> points) {
if(points.size()>3)
{
Set<Point> convexHull = new HashSet<Point>();
// 左上方的点必然在凸包中(左上方点的定义,首先若x最小,那么它为最左边的点,若有两个点的x同为最小,那么y值越小的点,就是最左边的点)
Point p0 = new Point(Double.MAX_VALUE, Double.MAX_VALUE);
Map<Point,Boolean>isinsert=new HashMap<>();
for (Point item : points) {
isinsert.put(item,false);
if (item.x() < p0.x() || (item.x() == p0.x() && item.y() < p0.y()))
p0 = item;
}
Point nowPoint = p0, tempPoint = p0;
double nowAngle = 0;
double minAngle = 360;
double tempAngle = 0;
double distance;
double maxdistance = -1;
do {
if(nowPoint!=p0){
isinsert.put(nowPoint,true);
}
convexHull.add(nowPoint);
for (Point item : points) {
if ((!convexHull.contains(item)||(item==p0&&ischanged(isinsert)))) {
tempAngle = calculateBearingToPoint11(nowAngle, nowPoint.x(), nowPoint.y(), item.x(), item.y());
distance = distance(item,nowPoint);
// 顺时针找下一个在凸包中的点,如果偏转角度相同,取距离更远的点(点的优先级1.偏转角度,2.点到上一个点的距离)
if (tempAngle < minAngle || ((tempAngle == minAngle) && (distance > maxdistance))) {
minAngle = tempAngle;
tempPoint = item;
maxdistance = distance;
}
}
}
minAngle = 360;
nowAngle = 0;
nowPoint = tempPoint;
} while (nowPoint!=p0);
return convexHull;
}
else{
return points;
}
}
public static boolean ischanged(Map<Point,Boolean>isinsert){
for(Map.Entry<Point, Boolean> entry : isinsert.entrySet()){
if(entry.getValue()==true){
return true;
}
}
return false;
}
private static double distance(Point p1, Point p2) {
return (p1.x() - p2.x()) * (p1.x() - p2.x()) + (p1.y() - p2.y()) * (p1.y() - p2.y());
}
public static double calculateBearingToPoint11(double currentBearing, double currentX, double currentY,
double targetX, double targetY) {
double angle = Math.toDegrees(Math.atan2(targetX - currentX, targetY - currentY));
double turnAngle = angle - currentBearing;
if (turnAngle < 0)
turnAngle += 360;
return turnAngle;
}