2

几天来,我一直在为这个问题绞尽脑汁……我看不出我的算法可能遗漏了什么。这就是这里的问题。

从我收集到的信息中,我以某种循环的 ccw 顺序获得积分。因此,我实现了一个 graham 扫描版本,通过确保它使用始终提供右转的点来寻找凸包。

我的算法适用于所有给定的测试输入和我可以提出的所有输入,但它不会被在线法官接受,这是作业“完成”所必需的。

无论如何,这是我的代码,如果有人能找到我所缺少的东西,我将永远欠你的债。

import java.util.Scanner;
import java.util.Vector;
import java.util.Arrays;
import java.util.Comparator;

public class Main {

public Main() {}

public void handlePoints(Point[] points) throws Exception {
    int m = 1;
    Vector<Point> convexHull = new Vector<Point>();
    // This is THE ONLY gaurunteed point to be in the hull - and it is the lowest left point so that's ok. 
    convexHull.add(points[0]);
    // Can be removed if ill-suited. 
    convexHull.add(points[1]);
    for (int i = 2; i < points.length; i++) {
        // Find the next valid point on the hull. 
        while (counterClockWise(convexHull.elementAt(m-1), convexHull.elementAt(m), points[i]) <= 0) {
            convexHull.removeElementAt(m);
            if (m > 1) {
                m -= 1;
            }
            // All points are colinear
            else if (i == points.length - 1) {
                break;
            }
            else {
                convexHull.add(points[i]);
                i++;
            }
        }
        convexHull.add(points[i]);
        m++;
    }   
    if (convexHull.size() <= 3) {
        throw new Exception();
    }

    String test = "" + convexHull.size() + '\n';
    for (Point p : convexHull) {
        test += p.x + " " + p.y + '\n';
    }
    System.out.print(test);
}

// Simply calculated whether or not the 3 points form a countedClockWise turn.
public int counterClockWise(Point p1, Point p2, Point p3) {
    return ((p2.x - p1.x) * (p3.y - p1.y)) - ((p2.y - p1.y) * (p3.x - p1.x));
}

// Rearranges the array to maintain its order but be started and ended by the point with the lowest y value
private static Point[] moveLowestToFront(Point[] array) {
    // Rearrange for y:
    int lowestY = 99999;
    int lowestIndex = 0;
    for (int i = 0; i < array.length; i++) {
        if (array[i].y < lowestY) {
            lowestY = array[i].y;
            lowestIndex = i;
        }
    }
    // Scan through again to see if there are any competing low-y values. 
    int lowestX = 99999;
    for (int i = 0; i < array.length; i++) {
        if (array[i].y == lowestY) {
            if (array[i].x < lowestX) {
                lowestX = array[i].x;
                lowestIndex = i;
            }
        }
    }
    Point[] rearrangedPoints = new Point[array.length];
    int j = 0;
    // Take from low to end cutting off repeated start point. 
    for (int i = lowestIndex; i < array.length - 1; i++) {
        rearrangedPoints[j] = array[i];
        j++;
    }
    // Throw the remaining and put them at the end.
    for (int i = 0; i < lowestIndex; i++) {
        rearrangedPoints[j] = array[i];
        j++;
    }
    // End the array with the repeated first point. 
    rearrangedPoints[array.length - 1] = array[lowestIndex];
    return rearrangedPoints;
}

public static void main(String[] args) throws Exception {
    Scanner sc = new Scanner(System.in);
    Main convexHullFinder = new Main();
    int numDataSets = sc.nextInt();
    System.out.println(numDataSets);
    for (int z = 0; z < numDataSets; z++) {
        int numPoints = sc.nextInt();
        Vector<Point> points = new Vector<Point>();
        // Read in all the points for this set. 
        points.add(new Point(sc.nextInt(), sc.nextInt()));
        int j = 1;
        for (int i = 1; i < numPoints; i++) {
            Point p = new Point(sc.nextInt(), sc.nextInt());
            // Remove repeated points. 
            if (p.x < 0 || p.y < 0) {
                throw new Exception();
            }
            if ( (p.x == points.elementAt(j-1).x) && (p.y == points.elementAt(j-1).y) ) {}
            else {
                points.add(p);
                j++;
            }
        }
        Point[] reducedPoints = points.toArray(new Point[points.size()]);

        // Rearrange the set to start and end on the lowest Y point. 
        reducedPoints = moveLowestToFront(reducedPoints);

        if (numPoints >= 3) {
            convexHullFinder.handlePoints(reducedPoints);
        }
        else {
            throw new Exception();
        }

        try { 
            System.out.println(sc.nextInt());
        }
        catch (Exception e) {

        }
    }
}
}

class Point {
public int x;
public int y;

public Point(int x, int y) {
    this.x = x;
    this.y = y;
}
}
4

1 回答 1

0

从它的声音来看,这些点是按照格雷厄姆扫描进行排序的。因此,我认为你的堆栈操作(handlePoints)可能是不对的。

我更习惯安德鲁的算法(格雷厄姆扫描的修改),但我相当确定你不应该在 while 循环的内部和外部向凸包添加点。原因是我相当确定无论使用哪种算法,while 循环的目的都是一样的。它是从凸包中删除无效点。但是,您有可能在 while 循环期间添加点。

我不确定这就是所有需要解决的问题,但我目前没有设置任何东西来运行 Java。

于 2012-12-24T08:46:49.653 回答