POJ3304 题意“:给N个线段,如果N个线段能找到一条直线L ,使得N个线段在L上投影至少有一个公共点,输出YES,否则输出NO
思路:如果存在L的话,能说明什么。。说明L的法线L’肯定能经过所有的线段
若存在一条直线L‘能经过所有线段,说明存在L’经过所有线段的两个端点
那么我们只要枚举两个端点P1P2,对每个直线P1P2 遍历所有线段i:1~N,用外积<=0来判断线段的两个端点L1L2是否在P1P2的两侧,如果找到一组P1P2就能输出YES了
(L1P1^L1P2 )*(L2P1^L2P2 )<0 ^代表外积,如下图
注意:要判断重复点,即P1P2有可能重点,那么只要加判一下就好了
代码如下:
#include
#include
#include
#include
typedef long long int ll;
using namespace std;
const double eps = 1e-8;
const double PI = acos(-1.0);
int sgn(double x)
{
if(fabs(x) < eps)return 0;
if(x < 0)return -1;
else return 1;
}
struct point
{
double x,y;
point() {} point(double _x,double _y)
{
x = _x;
y = _y;
} point operator -(const point &b)const
{
return point(x - b.x,y - b.y);
}
double operator ^(const point &b)const //叉积
{
return x*b.y - y*b.x;
}
double operator *(const point &b)const //点积
{
return x*b.x + y*b.y; //绕原点旋转角度B(弧度值),后x,y的变化
}
void transXY(double B)
{
double tx = x,ty = y;
x = tx*cos(B) - ty*sin(B);
y = tx*sin(B) + ty*cos(B);
}
}points[1005];
struct line
{
point s,e;
line() {}
line(point _s,point _e)
{
s = _s;
e = _e;
}
} lines[1005];
double xmult(point p0,point p1,point p2) //计算p0p1 X p0p2
{
return (p1-p0)^(p2-p0);
}
bool check(line a,int n)
{
if(sgn(a.s.x-a.e.x)==0&&sgn(a.s.y-a.e.y)==0)//重复点
return false;
int flag=0;
for(int i=0; i
0)//同侧 { return false; } } return true; } int main() { int T; cin>>T; while(T--) { int n; cin>>n; int num=0; for(int i=0; i
>t1>>t2>>t3>>t4; points[num++]=point(t1,t2); points[num++]=point(t3,t4); lines[i].s=point(t1,t2); lines[i].e=point(t3,t4); } int flag=0; if(n<3) flag=1; for(int i=0; i<num; i++) { for(int j=i+1; j<num; j++) { line lt1=line(points[i],points[j]); if(check(lt1,n)) { // cout<<lt1.s.x<<" "<<lt1.s.y<<" "<<i<<" "<<j<<" "<<endl; // cout<<lt1.e.x<<" "<<lt1.e.y<<" "<<i<<" "<<j<<" "<<endl; flag=1; break; } } if(flag) break; } if(flag) printf("Yes!\n"); else printf("No!\n"); } }sssssss