http://acm.pku.edu.cn/JudgeOnline/problem?id=3304
假设存在 符合题意的一条直线l ,它经过所有线段。 那么, 必可以通过旋转,平移等操作,使得该直线至少经过两个
#include <stdio.h>
#include <algorithm>
#include <iostream>
using namespace std;
#define FOR(i,s,e) for (int (i)=(s); (i) < (e);i++)
struct POINT
{
double x;
double y;
POINT(double a=0, double b=0) { x=a; y=b;} //constructor
};
struct LINESEG
{
POINT s;
POINT e;
LINESEG(POINT a, POINT b) { s=a; e=b;}
LINESEG() { }
};
struct LINE // 直线的解析方程 a*x+b*y+c=0 为统一表示,约定 a >= 0
{
double a;
double b;
double c;
LINE(double d1=1, double d2=-1, double d3=0) {a=d1; b=d2; c=d3;}
};
const double INF = 1E20;
const double EP = 1E-9;
const int MAXV = 300;
const double PI = 3.14159265;
double multiply(POINT sp,POINT ep,POINT op)
{
return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));
}
bool intersect_l(LINESEG u,LINESEG v)
{
return multiply(u.s,v.e,v.s)*multiply(v.e,u.e,v.s)>=0;
}
bool cmp(POINT a,POINT b)
{
return a.x < b.x || a.x == b.x && a.y < b.y;
}
int m;
int n;
POINT p[250];
LINESEG line[250];
int main()
{
// freopen("in.txt","r",stdin);
int t ;
scanf("%d",&t);
bool sign_judge;
while (t--)
{
m = 0;
scanf("%d",&n);
bool sign = true;
double x = 0;
FOR(i,0,n)
{
scanf("%lf%lf%lf%lf",&line[i].s.x,&line[i].s.y, &line[i].e.x, &line[i].e.y );
p[m++] = line[i].s;
p[m++] = line[i].e;
if (i == 0) x = line[i].s.x;
if (x != line[i].s.x || x != line[i].e.x)
sign = false;
}
if (sign)
printf("Yes!\n");
else
{
sign_judge = true;
sort(p,p+m,cmp);
// for (int i=0; i<m;i++)
// printf("%lf %lf\n",p[i].x,p[i].y);
for (int i=0; i<m && sign_judge; i++)
for (int j=i+1; j<m && sign_judge; j++)
if (p[i].x != p[j].x)
{
bool sign_help = true;
LINESEG light(p[i],p[j]);
for (int k=0; k<n; k++)
if (!intersect_l(line[k],light))
{
// printf("i=%d j=%d k=%d\n",i,j,k);
sign_help = false;
break;
}
if (sign_help)
{
sign_judge = false;
}
}
if (!sign_judge)
printf("Yes!\n");
else
printf("No!\n");
}
}
return 0;
}
端点。 于是,可以通过枚举所有任意两个端点所生成的直线,判断其是否经过所有线段。