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

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;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值