# 极其郁闷的ZJU 1081, 感觉算法应该没问题了, 可是就是WA掉了.

Program T_1081;
Const
Infinity = MaxInt;
MaxPoints = 100;

Type
CoordinateType = LongInt;

PointType = Record
x,y : CoordinateType;
End;

LineType = Record
P1, P2 : PointType;
End;

PolygonType = Record
P : Array [1..MaxPoints] Of PointType;
End;

Pointer = ^PolygonType;

Function Max(a,b : CoordinateType) : CoordinateType;
Begin
If (a>=b) Then Max:=a Else Max:=b;
End;

Function Min(a,b : CoordinateType) : CoordinateType;
Begin
If (a<=b) Then Min:=a Else Min:=b;
End;

Function Multiply(P1, P2, P0 : PointType) : CoordinateType;
Begin
Multiply := (P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y);
End;

Function Intersect (L1, L2 : LineType) : Boolean;
Begin
Intersect := (Max(L1.P1.x, L1.P2.x) >= Min(L2.P1.x, L2.P2.x)) AND
(Max(L2.P1.x, L2.P2.x) >= Min(L1.P1.x, L1.P2.x)) AND
(Max(L1.P1.y, L1.P2.y) >= Min(L2.P1.y, L2.P2.y)) AND
(Max(L2.P1.y, L2.P2.y) >= Min(L1.P1.y, L1.P2.y)) AND
(Multiply(L1.P2, L2.P1, L1.P1) * Multiply(L2.P2, L1.P2, L1.P1) >= 0) AND
(Multiply(L2.P2, L1.P2, L2.P1) * Multiply(L1.P1, L2.P2, L2.P1) >= 0)
End;

Function Online (L : LineType; P : PointType) : Boolean;
Begin
Online := (Multiply(L.P2, P, L.P1) = 0) AND
((P.x - L.P1.x) * (P.x - L.P2.x) <= 0) AND
((P.y - L.P1.y) * (P.y - L.P2.y) <= 0);
End;

Function InSameSide (L : LineType; P1, P2 : PointType) : Boolean;
Begin
InSameSide := (Multiply (L.P2, P1, L.P1) * Multiply(L.P2, P2, L.P1)) >= 0 ;
End;

Function InsidePolygon (Polygon : Pointer; n : LongInt; Q : PointType) : Boolean;
Var
L1, L2 : LineType;
c, i : LongInt;
i1, i2, i3 : LongInt;

Begin
c := 0; L1.P1 := Q; L1.P2 := Q; L1.P2.x := Infinity;

For i:=1 To n Do
Begin
i1 := (i+1) MOD n; i2 := (i+2) MOD n; i3 := (i+3) MOD n;
L2.P1 := Polygon^.P[i]; L2.P2 := Polygon^.P[i1];

If Online(L2, Q) Then
Begin
InsidePolygon := True;
Exit;
End;

If (Intersect(L1, L2) AND NOT Online(L1, L2.P1) AND NOT Online(L1, L2.P2)) OR
Online(L1, Polygon^.P[i1]) AND
(NOT Online(L1, Polygon^.P[i2]) AND NOT InSameSide(L1, Polygon^.P[i], Polygon^.P[i2]) OR
Online(L1, Polygon^.P[i3]) AND NOT InSameSide(L1, Polygon^.P[i], Polygon^.P[i3]))
Then Inc(c);
End;

InsidePolygon:=Odd(c);
End;

Var
Polygon : PolygonType;
Point : PointType;
Count, i, N, M : LongInt;

Begin
Count:=0;
While NOT EOF(Input) Do
Begin
If N=0 Then Exit;
Inc(Count);
Writeln('Problem ',Count,':');
For i:=1 To N Do

For i:=1 To M Do
Begin
If InsidePolygon(@Polygon, N, Point) Then
Writeln('Within')
Else
Writeln('Outside');
End;
Writeln;
End;
End.
-------------------------------------------------题目如下:
Points Within

Time limit: 30 Seconds Memory limit: 32768K
Total Submit: 158 Accepted Submit: 34

Statement of the Problem
Several drawing applications allow us to draw polygons and almost all of them allow us to fill them with some color. The task of filling a polygon reduces to knowing which points are inside it, so programmers have to colour only those points.

You're expected to write a program which tells us if a given point lies inside a given polygon described by the coordinates of its vertices. You can assume that if a point is in the border of the polygon, then it is in fact inside the polygon.

Input Format

The input file may contain several instances of the problem. Each instance consists of: (i) one line containing integers N, 0 < N < 100 and M, respectively the number of vertices of the polygon and the number of points to be tested. (ii) N lines, each containing a pair of integers describing the coordinates of the polygon's vertices; (iii) M lines, each containing a pair of integer coordinates of the points which will be tested for "withinness" in the polygon.

You may assume that: the vertices are all distinct; consecutive vertices in the input are adjacent in the polygon; the last vertex is adjacent to the first one; and the resulting polygon is simple, that is, every vertex is incident with exactly two edges and two edges only intersect at their common endpoint. The last instance is followed by a line with a 0 (zero).

Output Format

For the ith instance in the input, you have to write one line in the output with the phrase "Problem i:", followed by several lines, one for each point tested, in the order they appear in the input. Each of these lines should read "Within" or "Outside", depending on the outcome of the test. The output of two consecutive instances should be separated by a blank line.

Sample Input

3 1
0 0
0 5
5 0
10 2
3 2
4 4
3 1
1 2
1 3
2 2
0

Sample Output

Problem 1:
Outside

Problem 2:
Outside
Within
...全文
64 点赞 收藏 7

7 条回复

LeeMaRS 2002-09-12

starfish 2002-09-12

starfish 2002-09-11

//#define DEBUG

#include <iostream>
#include <cmath>
#ifdef DEBUG
#include <fstream>
#endif

using namespace std;

const double INFINITY = 1e10;
const double ESP = 1e-5;
const int MAX_N = 1000;

struct Point {
double x, y;
};

struct LineSegment {
Point pt1, pt2;
};

int n, m, count;
Point polygon[MAX_N];
Point P;

#ifdef DEBUG
ifstream fin("1081.in");
istream& in = fin;
ostream& out = cout;
#else
istream& in = cin;
ostream& out = cout;
#endif

inline double max(double x, double y)
{
return (x > y ? x : y);
}

inline double min(double x, double y)
{
return (x < y ? x : y);
}

// 计算叉乘 |P1P0| × |P2P0|
double Multiply(Point p1, Point p2, Point p0)
{
return ( (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y) );
}

// 判断线段是否包含点point
bool IsOnline(Point point, LineSegment line)
{
return( ( fabs(Multiply(line.pt1, line.pt2, point)) < ESP ) &&
( ( point.x - line.pt1.x ) * ( point.x - line.pt2.x ) <= 0 ) &&
( ( point.y - line.pt1.y ) * ( point.y - line.pt2.y ) <= 0 ) );
}

// 判断线段相交
bool Intersect(LineSegment L1, LineSegment L2)
{
return( (max(L1.pt1.x, L1.pt2.x) >= min(L2.pt1.x, L2.pt2.x)) &&
(max(L2.pt1.x, L2.pt2.x) >= min(L1.pt1.x, L1.pt2.x)) &&
(max(L1.pt1.y, L1.pt2.y) >= min(L2.pt1.y, L2.pt2.y)) &&
(max(L2.pt1.y, L2.pt2.y) >= min(L1.pt1.y, L1.pt2.y)) &&
(Multiply(L2.pt1, L1.pt2, L1.pt1) * Multiply(L1.pt2, L2.pt2, L1.pt1) >= 0) &&
(Multiply(L1.pt1, L2.pt2, L2.pt1) * Multiply(L2.pt2, L1.pt2, L2.pt1) >= 0)
);
}

// 判断点在多边形内
bool InPolygon(Point polygon[], int n, Point point)
{
if (n == 1) {
return ( (fabs(polygon.x - point.x) < ESP) && (fabs(polygon.y - point.y) < ESP) );
} else if (n == 2) {
LineSegment side;
side.pt1 = polygon;
side.pt2 = polygon;
return IsOnline(point, side);
}

int count = 0;
LineSegment line;
line.pt1 = point;
line.pt2.y = point.y;
line.pt2.x = - INFINITY;

for( int i = 0; i < n; i++ ) {
// 得到多边形的一条边
LineSegment side;
side.pt1 = polygon[i];
side.pt2 = polygon[(i + 1) % n];

if( IsOnline(point, side) ) {
return true;
}

// 如果side平行x轴则不作考虑
if( fabs(side.pt1.y - side.pt2.y) < ESP ) {
continue;
}

if( IsOnline(side.pt1, line) ) {
if( side.pt1.y > side.pt2.y ) count++;
} else if( IsOnline(side.pt2, line) ) {
if( side.pt2.y > side.pt1.y ) count++;
} else if( Intersect(line, side) ) {
count++;
}
}

return ( count % 2 == 1 );
}

int main()
{
count = 0;
in >> n;
while (n > 0) {
count++;
if (count > 1) out << endl;
out << "Problem " << count << ":" << endl;

in >> m;

for (int i = 0; i < n; i++) {
in >> polygon[i].x >> polygon[i].y;
}

for (int i = 0; i < m; i++) {
in >> P.x >> P.y;
if (InPolygon(polygon, n, P)) {
out << "Within" << endl;
} else {
out << "Outside" << endl;
}
}

n = 0;
in >> n;
}
return 0;
}

zyzyis 2002-09-11

================================================================

CSDN 论坛助手 Ver 1.0 B0402提供下载。 改进了很多，功能完备！

★ 浏览帖子速度极快！[建议系统使用ie5.5以上]。 ★ 多种帖子实现界面。
★ 保存帖子到本地[html格式]★ 监视您关注帖子的回复更新。
★ 可以直接发贴、回复帖子★ 采用XML接口，可以一次性显示4页帖子,同时支持自定义每次显示帖子数量。可以浏览历史记录！
★ 支持在线检测程序升级情况，可及时获得程序更新的信息。

★★ 签名 ●

Http://www.ChinaOK.net/csdn/csdn.zip
Http://www.ChinaOK.net/csdn/csdn.rar
Http://www.ChinaOK.net/csdn/csdn.exe [自解压]

zyzyis 2002-09-11

================================================================

CSDN 论坛助手 Ver 1.0 B0402提供下载。 改进了很多，功能完备！

★ 浏览帖子速度极快！[建议系统使用ie5.5以上]。 ★ 多种帖子实现界面。
★ 保存帖子到本地[html格式]★ 监视您关注帖子的回复更新。
★ 可以直接发贴、回复帖子★ 采用XML接口，可以一次性显示4页帖子,同时支持自定义每次显示帖子数量。可以浏览历史记录！
★ 支持在线检测程序升级情况，可及时获得程序更新的信息。

★★ 签名 ●

Http://www.ChinaOK.net/csdn/csdn.zip
Http://www.ChinaOK.net/csdn/csdn.rar
Http://www.ChinaOK.net/csdn/csdn.exe [自解压]

LeeMaRS 2002-09-11
555！是的，就是这么简单的一个题目！我的程序竟然WA掉了，所以我才很郁闷啊！我是第一次写计算几何的程序！谁能帮我看看是哪里出了问题呢？？

xiaonian_3654 2002-09-11

3.2w+