【发布时间】:2012-01-09 03:43:11
【问题描述】:
我已经在 interviewstreet 解决了多边形问题,但它似乎太慢了。解决问题的最佳方法是什么?
X-Y 平面上有 N 个点,坐标为整数坐标 (xi, yi)。给定一组多边形,其所有边都平行于轴(换句话说,多边形的所有角度都是 90 度角,所有线都在基本方向上。没有对角线)。对于每个多边形,您的程序应该找到位于其中的点数(位于多边形边界上的点也被认为在多边形内)。
输入:
第一行两个整数 N 和 Q。下一行包含 N 个空格分隔的整数坐标 (xi,yi)。 Q 查询如下。每个查询由第一行中的单个整数 Mi 组成,然后是 Mi 空间分隔的整数坐标 (x[i][j],y[i][j]),以顺时针顺序指定查询多边形的边界。
多边形是垂直线段和水平线段的交替序列。 多边形有 Mi 边,其中 (x[i][j],y[i][j]) 连接到 (x[i][(j+1)%Mi], y[i][(j+1 )%Mi]。 对于每个 0
输出:
对于每个查询,在单独的一行中输出查询多边形内的点数。
示例输入 #1:
16 2
0 0
0 1
0 2
0 3
1 0
1 1
1 2
1 3
2 0
2 1
2 2
2 3
3 0
3 1
3 2
3 3
8
0 0
0 1
1 1
1 2
0 2
0 3
3 3
3 0
4
0 0
0 1
1 1
1 0
示例输出 #1:
16
4
示例输入 #2:
6 1
1 1
3 3
3 5
5 2
6 3
7 4
10
1 3
1 6
4 6
4 3
6 3
6 1
4 1
4 2
3 2
3 3
示例输出 #2:
4
约束:
1
我对上述语言或伪代码的解决方案感兴趣。
编辑:这是我的代码,但它是 O(n^2)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace Polygon
{
// avoding System.Drawing dependency
public struct Point
{
public int X { get; private set; }
public int Y { get; private set; }
public Point(int x, int y)
: this()
{
X = x;
Y = y;
}
public override int GetHashCode()
{
return X ^ Y;
}
public override bool Equals(Object obj)
{
return obj is Point && this == (Point)obj;
}
public static bool operator ==(Point a, Point b)
{
return a.X == b.X && a.Y == b.Y;
}
public static bool operator !=(Point a, Point b)
{
return !(a == b);
}
}
public class Solution
{
static void Main(string[] args)
{
BasicTestCase();
CustomTestCase();
// to read from STDIN
//string firstParamsLine = Console.ReadLine();
//var separator = new char[] { ' ' };
//var firstParams = firstParamsLine.Split(separator);
//int N = int.Parse(firstParams[0]);
//int Q = int.Parse(firstParams[1]);
//List<Point> points = new List<Point>(N);
//for (int i = 0; i < N; i++)
//{
// var coordinates = Console.ReadLine().Split(separator);
// points.Add(new Point(int.Parse(coordinates[0]), int.Parse(coordinates[1])));
//}
//var polygons = new List<List<Point>>(Q); // to reduce realocation
//for (int i = 0; i < Q; i++)
//{
// var firstQ = Console.ReadLine().Split(separator);
// int coordinatesLength = int.Parse(firstQ[0]);
// var polygon = new List<Point>(coordinatesLength);
// for (int j = 0; j < coordinatesLength; j++)
// {
// var coordinates = Console.ReadLine().Split(separator);
// polygon.Add(new Point(int.Parse(coordinates[0]), int.Parse(coordinates[1])));
// }
// polygons.Add(polygon);
//}
//foreach (var polygon in polygons)
//{
// Console.WriteLine(CountPointsInPolygon(points, polygon));
//}
}
private static void BasicTestCase()
{
List<Point> points = new List<Point>(){ new Point(0, 0),
new Point(0, 1),
new Point(0, 2),
new Point(0, 3),
new Point(1, 0),
new Point(1, 1),
new Point(1, 2),
new Point(1, 3),
new Point(2, 0),
new Point(2, 1),
new Point(2, 2),
new Point(2, 3),
new Point(3, 0),
new Point(3, 1),
new Point(3, 2),
new Point(3, 3) };
List<Point> polygon1 = new List<Point>(){ new Point(0, 0),
new Point(0, 1),
new Point(2, 1),
new Point(2, 2),
new Point(0, 2),
new Point(0, 3),
new Point(3, 3),
new Point(3, 0)};
List<Point> polygon2 = new List<Point>(){ new Point(0, 0),
new Point(0, 1),
new Point(1, 1),
new Point(1, 0),};
Console.WriteLine(CountPointsInPolygon(points, polygon1));
Console.WriteLine(CountPointsInPolygon(points, polygon2));
List<Point> points2 = new List<Point>(){new Point(1, 1),
new Point(3, 3),
new Point(3, 5),
new Point(5, 2),
new Point(6, 3),
new Point(7, 4),};
List<Point> polygon3 = new List<Point>(){ new Point(1, 3),
new Point(1, 6),
new Point(4, 6),
new Point(4, 3),
new Point(6, 3),
new Point(6, 1),
new Point(4, 1),
new Point(4, 2),
new Point(3, 2),
new Point(3, 3),};
Console.WriteLine(CountPointsInPolygon(points2, polygon3));
}
private static void CustomTestCase()
{
// generated 20 000 points and polygons
using (StreamReader file = new StreamReader(@"in3.txt"))
{
string firstParamsLine = file.ReadLine();
var separator = new char[] { ' ' };
var firstParams = firstParamsLine.Split(separator);
int N = int.Parse(firstParams[0]);
int Q = int.Parse(firstParams[1]);
List<Point> pointsFromFile = new List<Point>(N);
for (int i = 0; i < N; i++)
{
var coordinates = file.ReadLine().Split(separator);
pointsFromFile.Add(new Point(int.Parse(coordinates[0]), int.Parse(coordinates[1])));
}
var polygons = new List<List<Point>>(Q); // to reduce realocation
for (int i = 0; i < Q; i++)
{
var firstQ = file.ReadLine().Split(separator);
int coordinatesLength = int.Parse(firstQ[0]);
var polygon = new List<Point>(coordinatesLength);
for (int j = 0; j < coordinatesLength; j++)
{
var coordinates = file.ReadLine().Split(separator);
polygon.Add(new Point(int.Parse(coordinates[0]), int.Parse(coordinates[1])));
}
polygons.Add(polygon);
}
foreach (var polygon in polygons)
{
Console.WriteLine(CountPointsInPolygon(pointsFromFile, polygon));
}
}
}
public static int CountPointsInPolygon(List<Point> points, List<Point> polygon)
{
// TODO input check
polygon.Add(polygon[0]); // for simlicity
// check if any point is outside of the bounding box of the polygon
var minXpolygon = polygon.Min(p => p.X);
var maxXpolygon = polygon.Max(p => p.X);
var minYpolygon = polygon.Min(p => p.Y);
var maxYpolygon = polygon.Max(p => p.Y);
// ray casting algorithm (form max X moving to point)
int insidePolygon = 0;
foreach (var point in points)
{
if (point.X >= minXpolygon && point.X <= maxXpolygon && point.Y >= minYpolygon && point.Y <= maxYpolygon)
{ // now points are inside the bounding box
isPointsInside(polygon, point, ref insidePolygon);
} // else outside
}
return insidePolygon;
}
private static void isPointsInside(List<Point> polygon, Point point, ref int insidePolygon)
{
int intersections = 0;
for (int i = 0; i < polygon.Count - 1; i++)
{
if (polygon[i] == point)
{
insidePolygon++;
return;
}
if (point.isOnEdge(polygon[i], polygon[i + 1]))
{
insidePolygon++;
return;
}
if (Helper.areIntersecting(polygon[i], polygon[i + 1], point))
{
intersections++;
}
}
if (intersections % 2 != 0)
{
insidePolygon++;
}
}
}
static class Helper
{
public static bool isOnEdge(this Point point, Point first, Point next)
{
// onVertical
if (point.X == first.X && point.X == next.X && point.Y.InRange(first.Y, next.Y))
{
return true;
}
//onHorizontal
if (point.Y == first.Y && point.Y == next.Y && point.X.InRange(first.X, next.X))
{
return true;
}
return false;
}
public static bool InRange(this int value, int first, int second)
{
if (first <= second)
{
return value >= first && value <= second;
}
else
{
return value >= second && value <= first;
}
}
public static bool areIntersecting(Point polygonPoint1, Point polygonPoint2, Point vector2End)
{
// "move" ray up for 0.5 to avoid problem with parallel edges
if (vector2End.X < polygonPoint1.X )
{
var y = (vector2End.Y + 0.5);
var first = polygonPoint1.Y;
var second = polygonPoint2.Y;
if (first <= second)
{
return y >= first && y <= second;
}
else
{
return y >= second && y <= first;
}
}
return false;
}
}
}
【问题讨论】:
-
也许你可以在 makemycode.stackexchange.com 中找到答案(开玩笑)
-
您希望用哪种语言回答?
-
任何?甚至是文字描述和比光线投射更好的东西:)
-
如果您发布了一些示例代码,那么人们可能会提出改进建议
标签: c# java c++ python algorithm