题意
给定n条线段,确定是否存在一条直线,使得这n条线段在这条直线上的投影具有公共点。
n<=100
sol
非常妙的一个题。
我们考虑如果所有线段的投影有重合部分,那么我们可以在重合部分上做一条垂线经过所有点
同时我们平移一下这个直线,一定可以与某个点重合。
然后考虑旋转一下,一定可以交于某个最近的点(最近的定义是旋转最小的角度与之相交)
那么我们就搞出了一个(n^3)的做法:暴力枚举两个点构成的直线,判断是否与所有点相交
判断直线与线段相交可以用叉积
如果线段上的两点与直线的端点连线的叉积均同号的话,说明线段在直线的两侧。
否则说明相交
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; const int maxn = 1001; const double eps = 1e-10; int n; struct point { double x, y; point operator - (const point &rhs) const { return {x - rhs.x, y - rhs.y}; } double operator ^ (const point &rhs) const { return x * rhs.y - y * rhs.x; } bool operator == (const point &rhs) const { return (x - rhs.x) < eps && (y -rhs.y) < eps; } }; struct l { point a, b; }; point line[maxn][2]; int dcmp(double x) { if(fabs(x) < eps) return 0; return x > 0 ? 1 : -1; } bool judge(l l1, l l2) { point tmp = l1.a - l1.b; bool flag = dcmp(dcmp(tmp ^ (l2.b - l1.b)) * dcmp(tmp ^ (l2.a - l1.b))) != 1; return flag; } bool check(point a, point b) { if(a == b) return 0; for(int i = 1; i <= n; i++) if(!judge({a, b}, {line[i][0], line[i][1]})) return 0; return 1; } void solve() { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%lf %lf %lf %lf", &line[i][0].x, &line[i][0].y, &line[i][1].x, &line[i][1].y); for(int i = 1; i <= n; i++) for(int j = 0; j < 2; j++) for(int k = 1; k <= n; k++) for(int l = 0; l < 2; l++) if(check(line[i][j], line[k][l])) {puts("yes!"); return ;} puts("no!"); } int main() { int t; scanf("%d", &t); for(; t; t--, solve()); }
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/605216.html