题目描述
在平面中给定n个线段,编写一个程序,确定是否存在一条直线,使得在描述这些线段的位置之后,所有线段至少有一个重合点。
输入
输入以t开头,显示测试样例的数量,然后,t个测试样例在接下来的行数。每个测试样例以一行包含一个正整数n≤100显示线段的数量。在那之后,N行包含四个实数x1,y1,x2,y2跟随,以(x1,y1),(x2,y2)是一个线段的两个端点坐标。
输出
对于每个测试样例,您的程序必须输出“Yes!”如果有符合题目要求的行存在,必须输出“No!”否则。你必须假设A和B两浮点数相等,如果| A,B |<10-8。
分析
首先我们发现如果所需要的直线是存在的话,那么我们可以不断枚举它的斜率来找到这条直线,但是因为斜率是个实数,枚举它肯定不大可能。
因为是个无法枚举的很大的数,所以我想到了离散
这时候再推论一下,当这条直线存在时,它斜率偏转的直线肯定在两个线段的任意端点上
那么就比较简单了,无限的点离散到数组里,就只用枚举极端情况了
枚举两个线段,然后判断过任意两个端点的直线是否过其他所有线段,若是则就找到了
#include <iostream>
#include <cstdio>
#include <cmath>
#define sm 0.00000001
using namespace std;
int t,n;
struct F
{
double x,y;
}s[101][2];
int i,j;
bool b;
double cp(double x1,double y1,double x2,double y2,double x0,double y0)
{
double u=(x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);
return u;
}
bool dist(double x1,double y1,double x2,double y2)
{
return abs(x1-x2)<sm&&abs(y1-y2)<sm;
}
bool across(double x1,double y1,double x2,double y2)
{
if (dist(x1,y1,x2,y2)) return false;
for (int i=1;i<=n;i++)
if (cp(x1,y1,x2,y2,s[i][0].x,s[i][0].y)*cp(x1,y1,x2,y2,s[i][1].x,s[i][1].y)>sm) return false;
return true;
}
int main()
{
scanf("%d",&t);
while (--t>=0)
{
scanf("%d",&n);
for (i=1;i<=n;i++)
scanf("%lf%lf%lf%lf",&s[i][0].x,&s[i][0].y,&s[i][1].x,&s[i][1].y);
b=0;
if (n<=2) b=1;
else
for (i=1;i<=n;i++)
{
for (j=i+1;j<=n;j++)
{
if (across(s[i][0].x,s[i][0].y,s[j][0].x,s[j][0].y))
b=1;
if (across(s[i][0].x,s[i][0].y,s[j][1].x,s[j][1].y))
b=1;
if (across(s[i][1].x,s[i][1].y,s[j][0].x,s[j][0].y))
b=1;
if (across(s[i][1].x,s[i][1].y,s[j][1].x,s[j][1].y))
b=1;
if (b)
break;
}
if (b)
break;
}
if (b) printf("Yes!\n");
else printf("No!\n");
}
}
本文介绍了一种通过检查多个线段是否存在共同交点的方法。利用斜率和端点坐标进行判断,实现了一个高效的算法,该算法能判断在一组线段中是否存在一条直线贯穿所有线段。
1396

被折叠的 条评论
为什么被折叠?



