题目链接:点击打开链接
题意:给出一些线段,判断是否存在一条直线,使所有线段在这条直线上的投影都有公共部分(project是投影的意思)
如果有公共部分,那么做这公共部分的垂线一定经过所有线段,本题数据量只有100,所以可以枚举任意两个端点看是否穿过所有线段。
判断线段相交可以参考这里:判断线段相交
本题是判断线段和直线相交,所以当叉积等于0时就可以确定端点在直线上,但如果是线段就不行,还需判断端点是否在线段上,因为可能在线段延长线上。
枚举两端点时需要注意要判断两端点是否重合,如果重合,对于一个点所有的线段算叉积一定等于0,WA了几次。
代码:
#include <iostream>
using namespace std;
#include <cstdio>
#include <cstring>
#define eps 1e-8
int n,len;
struct Point{
double x,y;
Point(){}
Point(double x,double y):x(x),y(y){}
Point operator - (Point obj){
return Point(x-obj.x,y-obj.y);
}
}P[300];
double fabs(double n){
return n>0?n:-n;
}
struct seg{
Point a,b;
}S[105];
double Cross(Point a,Point b){
return a.x*b.y-b.x*a.y;
}
double Dot(Point a,Point b){
return a.x*b.x+a.y*b.y;
}
int dcmp(double a){
if(fabs(a)<eps) return 0;
return a>0?1:-1;
}
bool Seginter(Point a,Point b,Point c,Point d){
double t1=Cross(a-d,c-d);
double t2=Cross(b-d,c-d);
return (dcmp(t1)*dcmp(t2)<=0);
}
bool solve(){
for(int i=1;i<=len;i++){
for(int j=i+1;j<=len;j++){
if(!dcmp(P[i].x-P[j].x)&&!dcmp(P[i].y-P[j].y))continue;
for(int k=1;k<=n;k++){
if(!Seginter(S[k].a,S[k].b,P[i],P[j])) break;
if(k==n) return 1;
}
}
}
return 0;
}
void init(){
int pnum=0;
for(int i=1;i<=n;i++){
scanf("%lf%lf%lf%lf",&S[i].a.x,&S[i].a.y,&S[i].b.x,&S[i].b.y);
P[++pnum]=S[i].a;
P[++pnum]=S[i].b;
}
len=pnum;
}
int main(){
int T;
cin>>T;
while(T--){
scanf("%d",&n);
init();
if(solve()) printf("Yes!\n");
else printf("No!\n");
}
return 0;
}
本文介绍了一种判断多个线段是否能在某直线上找到公共投影的方法。通过枚举线段端点并检查是否所有线段都与该直线相交来解决此问题。详细解释了如何判断线段与直线的相交情况。
146

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



