1.https://codeforces.com/problemset/problem/793/C 2300的計算幾何真惡心啊
題意:n條射線,問全部到達一個矩形"内部"的時間
思路:1.如果p1在内部,那就隻有一個時間點,如果在外部,射入會有一個或兩個時間點.
2.獲得一段時間段後,取交集.
注意:如果點在邊緣,而且射線方向平行與x,y軸,那隻會從矩形邊緣擦過,輸出-1
還有一個,我是先判斷一條直線和邊框直線有沒有交點,然後判斷交點在射線上,再判斷交點線上段上.挺麻煩.
交點在射線上用向量判斷同方向,
const int N = 1e5 + 50;
const int INF = 0x7fffffff;
const double eps = 1e-9;
const double PI = acos(-1);
int sgn(double x) {
if(fabs(x) < eps)return 0;
else return x<0?-1:1;
}
struct Point {
double x,y;
Point() {}
Point(double x,double y):x(x),y(y) {}
Point operator + (Point B) {
return Point(x+B.x,y+B.y);
}
Point operator - (Point B) {
return Point(x-B.x,y-B.y);
}
Point operator /(double k) {
return Point(x/k,y/k);
}
bool operator == (Point B) {
return x == B.x && y == B.y;
}
};
struct Line {
Point p1,p2;//線上的兩個點
Line() {}
Line(Point p1,Point p2):p1(p1),p2(p2) {}
};
double Distance(Point A,Point B) {
return hypot(A.x-B.x,A.y-B.y);
// return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);
}
double Cross(Point a,Point b) {
return a.x*b.y-a.y*b.x;
}
typedef Point Vector;
double Dot(Vector A,Vector B) {
return A.x*B.x + A.y*B.y; //點積
}
//點和直線關系:1 在左側;2 在右側;0 在直線上
int Point_line_relation(Point p,Line v) {
int c = sgn(Cross(p-v.p1,v.p2-v.p1));
if(c < 0)return 1; //1:p在v的左邊
if(c > 0)return 2; //2:p在v的右邊
return 0; //0:p在v上
}
//兩直線關系:0 平行,1 重合,2 相交
int Line_relation(Line v1, Line v2) {
if(sgn(Cross(v1.p2-v1.p1,v2.p2-v2.p1)) == 0) {
if(Point_line_relation(v1.p1,v2)==0) return 1;//1 重合
else return 0;//0 平行
}
return 2; //2 相交
}
//求兩直線ab和cd的交點
//調用前要保證兩直線不平行或重合
Point Cross_point(Point a,Point b,Point c,Point d) { //Line1:ab, Line2:cd
double s1 = Cross(b-a,c-a);
double s2 = Cross(b-a,d-a); //叉積有正負
return Point(c.x*s2-d.x*s1,c.y*s2-d.y*s1)/(s2-s1);
}
// 點和線段的關系:0 點p不線上段v上;1 點p線上段v上。
bool Point_on_seg(Point p, Line v) {
return sgn(Cross(p-v.p1, v.p2-v.p1)) == 0 && sgn(Dot(p - v.p1,p- v.p2)) <=0;
}
bool Point_on_sx(Point a,Line p) {
if((a.x-p.p1.x)*(p.p2.x-p.p1.x) < 0)return false;
if((a.y-p.p1.y)*(p.p2.y-p.p1.y) < 0)return false;
return true;
}
int n;
Point A,B,p[N];
Line l[5];
Line x[N];
double dis[N][2];
int tot=0;
void work() {
scanf("%d",&n);
scanf("%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y);
l[0] = Line(Point(A.x,A.y),Point(B.x,A.y));
l[1] = Line(Point(B.x,A.y),Point(B.x,B.y));
l[2] = Line(Point(B.x,B.y),Point(A.x,B.y));
l[3] = Line(Point(A.x,B.y),Point(A.x,A.y));
for(int i=0; i<n; i++) {
double nx,ny;
scanf("%lf%lf%lf%lf",&p[i].x,&p[i].y,&nx,&ny);
x[i] = Line(p[i],p[i]+Point(nx,ny));
}
int f=1;
for(int i=0; i<n; i++) {
//判斷從邊緣擦過的情況
if(p[i].x == A.x || p[i].x == B.x || p[i].y == A.y || p[i].y == B.y) {
if(sgn(x[i].p2.x-x[i].p1.x) == 0 || sgn(x[i].p2.y-x[i].p1.y) == 0) {
f=0;
break;
}
}
tot=0;
//記錄兩個時間點
for(int j=0; j<4; j++) {
if(Line_relation(x[i],l[j]) == 2 ) {
Point z = Cross_point(x[i].p1,x[i].p2,l[j].p1,l[j].p2);
if(Point_on_sx(z,x[i]) && Point_on_seg(z,l[j])) { //點在射線上
double dd = Distance(p[i],z);
//可能存在經過三條邊(經過一個頂點)甚至兩個頂點...要特判
if(tot == 0 || (tot == 1 && fabs(dis[i][0] - dd) > eps) ||
(tot == 2 && fabs(dis[i][0] - dd) > eps && fabs(dis[i][1]-dd)>eps))
dis[i][tot++] = dd;
}
}
}
int ok = 0;
//如果在内部,特殊處理
if(p[i].x >= A.x && p[i].x <= B.x && p[i].y >= A.y && p[i].y <= B.y) {
if(tot != 2) {
tot = 2;
ok = 1;
dis[i][1] = dis[i][0];
dis[i][0] = 0.0;
}
}
//不在内部而且有兩個交點在同一點 -> 經過一個矩形頂點
if(tot != 2 || (!ok && fabs(dis[i][0] - dis[i][1]) < eps)) {
f = 0;
break;
}
if(dis[i][0] > dis[i][1])swap(dis[i][0],dis[i][1]);
}
if(f == 0)printf("-1
");
else {
double l=0,r=100000000;
for(int i=0; i<n; i++) {
l = max(l,dis[i][0]/Distance(x[i].p1,x[i].p2));
r = min(r,dis[i][1]/Distance(x[i].p1,x[i].p2));
}
if(l >= r ) printf("-1
");
else {
printf("%.8f
",l);
}
}
}