现在的位置: 首页 > 综合 > 正文

POJ 3304 Segments(计算几何 判断直线与线段相交)

2013年09月05日 ⁄ 综合 ⁄ 共 2979字 ⁄ 字号 评论关闭
Segments
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 7833   Accepted: 2363
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, nlines containing
four real numbers x1 y1 x2 y2 follow, in which (x1y1) and (x2y2) 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!

Source

这个题目个人认为不简单,要考虑的情况和精度控制,还涉及到一个问题的转换,我wa好多次

题目意思是给你一系列线段,问你是否存在一条直线使所有线段在这条直线上的投影存在一个公共点

这个问题转换为是否存在一条直线使每条线段和这条直线存在交点

解释一下:

现在假设有一条直线与这里所有线段都有一个交点,那么现在作另外一条直线垂直于这条直线

那么题目中的所有线段全部向这条直线投影,所有投影区域一定相交于刚才两条直线的交点,也就是垂足

这样这个题目就成功完成了转换

下面就是注意几点问题:

第一是精度控制,这个是计算几何中常见的问题

第二是在枚举任意两个点组成的直线后要判断这两个点是否相等,如果相等那么直接淘汰,因为长度为0的线段X乘一定还是0,这样误导结果

#include <iostream>
#include <stdio.h>
#include <cmath>
#include <string.h>
#include <algorithm>
using namespace std;
#define EPS 1e-8
struct point
{
double x;
double y;
};
struct line
{
point a;
point b;
}my_line[150];
int rec[150];
int n;
double xmulit(point &a,point &b,point &c)//a b X a c
{
return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
bool across(point &a,point &b,point &c,point &d)//直线ab和线段cd是否相交
{
double p=xmulit(a,b,c),p1=xmulit(a,b,d);
if( fabs(p1) <= EPS || fabs(p) <= EPS ) return true;
if( p*p1 <= 1e-8 )
return true;
return false;
}
bool is_equal(point &a,point &b)
{
return (fabs(a.x-b.x) <= EPS) && (fabs(a.y-b.y) <=EPS);
}
int main()
{
int t,i,j,k;
bool flag;
scanf("%d",&t);
flag=false;
while(t--)
{
flag=false;
memset(rec,0,sizeof(rec));
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%lf%lf%lf%lf",&my_line[i].a.x,&my_line[i].a.y,&my_line[i].b.x,&my_line[i].b.y);
}
for(i=0;i<n;i++)
{
for(k=0;k<n;k++)//这里不用判断,因为线段一定不会是两个点接近相等
{
if(k!=i && !across(my_line[i].a,my_line[i].b,my_line[k].a,my_line[k].b))
break;
}
if(n==k)
{
i=1000;
j=1000;
flag=true;
break;
}
for(j=i+1;j<n;j++)
{
if(!is_equal(my_line[i].a,my_line[j].a))
{
for(k=0;k<n;k++)
{
if(!across(my_line[i].a,my_line[j].a,my_line[k].a,my_line[k].b))
break;
}
if(n==k)
{
i=1000;
j=1000;
flag=true;
break;
}
}
if(!is_equal(my_line[i].a,my_line[j].b))
{
for(k=0;k<n;k++)
{
if(!across(my_line[i].a,my_line[j].b,my_line[k].a,my_line[k].b))
break;
}
if(n==k)
{
i=1000;
j=1000;
flag=true;
break;
}
if(!is_equal(my_line[i].b,my_line[j].a))
{
for(k=0;k<n;k++)
{
if(!across(my_line[i].b,my_line[j].a,my_line[k].a,my_line[k].b))
break;
}
if(n==k)
{
i=1000;
j=1000;
flag=true;
break;
}
}
}
if(!is_equal(my_line[i].b,my_line[j].b))
{
for(k=0;k<n;k++)
{
if(!across(my_line[i].b,my_line[j].b,my_line[k].a,my_line[k].b))
break;
}
if(n==k)
{
i=1000;
j=1000;
flag=true;
break;
}
}
}
}
if(!flag)
printf("No!\n");
else
printf("Yes!\n");
}
return 0;
}

抱歉!评论已关闭.