1. 程式人生 > >ACM-計算幾何之Segments——poj3304

ACM-計算幾何之Segments——poj3304

Segments

Description

Given n segments in the two dimensional space, write a program, which determines if there exists a line such that after projecting these segments on it, all projected segments have at least one point in common.

Input
Input begins with a number T showing the number of test cases and then, T test cases follow. Each test case begins with a line containing a positive integer n ≤ 100 showing the number of segments. After that, n lines containing four real numbers x1 y1 x2 y2 follow, in which (x1, y1) and (x2, y2) are the coordinates of the two endpoints for one of the segments.

Output

For each test case, your program must output "Yes!", if a line with desired property exists and must output "No!" otherwise. You must assume that two floating point numbers a and b are equal if |a - b| < 10-8.

Sample Input
3
2
1.0 2.0 3.0 4.0
4.0 5.0 6.0 7.0
3
0.0 0.0 0.0 1.0
0.0 1.0 0.0 2.0
1.0 1.0 2.0 1.0
3
0.0 0.0 0.0 1.0
0.0 2.0 0.0 3.0

1.0 1.0 2.0 1.0

Sample Output
Yes!
Yes!

No!

求是否存在一條直線可以與列出的所有線段相交。

解題:如果存在這麼一條直線,必定過平面中的兩個點,

所以任意窮舉兩個點所在的直線與所有線段判斷是否相交。

這道題還有注意精度問題。

#include <iostream>
#define MAX 201
using namespace std;

int n;
// 精度判定
const double eps = 1E-8;
int sig(double d)
{
    return (d>eps) - (d<-eps);
}
struct Point
{
    double x,y;

}point[MAX];

double cross(Point &o,Point& a,Point &b)
{
    return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
}

//判斷直線ab是否與線段cd相交
//0 不相交
//1 規範相交
//2 不規範相交
int segLineCross(Point &a,Point &b,Point &c,Point &d)
{
    int d1,d2;
    d1 = sig(cross(a,b,c));
    d2 = sig(cross(a,b,d));
    if((d1^d2)==-2)//注意加小括號,^的優先順序比==低
        return 1;
    if(d1==0 || d2==0)
        return 2;
    return 0;
}

bool Test(Point &a,Point &b)//判斷直線ab是否與所有線段相交
{
    int i;
    if(sig(a.x-b.x)==0 && sig(a.y-b.y)==0)//★判斷重複點
        return false;
    for(i=0;i<2*n;i+=2)
        if(segLineCross(a,b,point[i],point[i+1])==0)
            return false;
    return true;
}

bool Find()
{
    int i,j;
    for(i=0;i<2*n;++i)
        for(j=0;j<2*n;++j)
            if(Test(point[i],point[j]))
                return true;
    return false;
}
int main()
{
    int test,i;
    cin >> test;
    while(test--)
    {
        cin >> n;
        for(i=0;i<2*n;++i)
            cin>>point[i].x>>point[i].y;

        if(Find())
            cout << "Yes!" << endl;
        else
            cout << "No!" << endl;
    }
    return 0;
}