2 0.00 0.00 1.00 1.00 0.00 1.00 1.00 0.00 3 0.00 0.00 1.00 1.00 0.00 1.00 1.00 0.000 0.00 0.00 1.00 0.00 0
求线段相交分为两个讨论
1.规范相交
2.不规范相交
对于1 直接跨立实验叉积搞定
对与2 在跨立实验后 发现有三点共线情况 利用点积判断第二个向量的那个点是否落在第一个向量中间
几点注意
1.写一个doublesgn函数 来避免-0.00001当做小于0的情况
这是根据上述定义写的丑陋代码
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <ctime> #include <algorithm> #include <iostream> #include <sstream> #include <string> #define oo 0x13131313 #define exp 10e-6 using namespace std; struct point { double x; double y; }; point start[101],end[101]; int N,ans=0; void init() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); } int dblcmp(double d) { if(fabs(d)<exp) return 0; else return (d>0)?1:-1; } void input() { ans=0; for(int i=1;i<=N;i++) { scanf("%lf%lf%lf%lf",&start[i].x,&start[i].y,&end[i].x,&end[i].y); } } double XX(double x1,double y1,double x2,double y2) { return x1*y2-x2*y1; } int cross(point &a,point &b,point &c) { return dblcmp(XX(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y)); } double DX(double x1,double y1,double x2,double y2) { return x1*x2+y1*y2; } int Dcross(point &a,point &b,point &c) { return dblcmp(DX(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y)); } int panX(point &S1,point &E1,point &S2,point &E2) { int SS2=cross(S1,E1,S2),EE2=cross(S1,E1,E2),SS1=cross(S2,E2,S1),EE1=cross(S2,E2,E1); int a1=SS2*EE2; int a2=SS1*EE1; if(a1==1||a2==1) return 0; if(a1==-1&&a2==-1) return 1; if(a1==0) { if(SS2==0) { if(Dcross(S1,E1,S2)>=0&&Dcross(E1,S1,S2)>=0) return 1; else return 0; } if(EE2==0) { if(Dcross(S1,E1,E2)>=0&&Dcross(E1,S1,E2)>=0) return 1; else return 0; } } if(a2==0) { if(SS1==0) { if(Dcross(S2,E2,S1)>=0&&Dcross(E2,S2,S1)>=0) return 1; else return 0; } if(EE1==0) { if(Dcross(S2,E2,E1)>=0&&Dcross(E2,S2,E1)>=0) return 1; else return 0; } } return 1; } void solve() { for(int i=1;i<=N;i++) for(int j=i+1;j<=N;j++) { if(panX(start[i],end[i],start[j],end[j])) ans++; } } int main() { // init(); while(scanf("%d",&N)!=EOF&&N) { input(); solve(); cout<<ans<<endl; } return 0; }
傻逼的发现 点积那里只要判断一次就好了 改了改
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <ctime> #include <algorithm> #include <iostream> #include <sstream> #include <string> #define oo 0x13131313 #define exp 10e-6 using namespace std; struct point { double x; double y; }; point start[101],end[101]; int N,ans=0; void init() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); } int dblcmp(double d) { if(fabs(d)<exp) return 0; else return (d>0)?1:-1; } void input() { ans=0; for(int i=1;i<=N;i++) { scanf("%lf%lf%lf%lf",&start[i].x,&start[i].y,&end[i].x,&end[i].y); } } double XX(double x1,double y1,double x2,double y2) { return x1*y2-x2*y1; } int cross(point &a,point &b,point &c) { return dblcmp(XX(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y)); } double DX(double x1,double y1,double x2,double y2) { return x1*x2+y1*y2; } int Dcross(point &a,point &b,point &c) { return dblcmp(DX(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y)); } int panX(point &S1,point &E1,point &S2,point &E2) { int SS2=cross(S1,E1,S2),EE2=cross(S1,E1,E2),SS1=cross(S2,E2,S1),EE1=cross(S2,E2,E1); int a1=SS2*EE2; int a2=SS1*EE1; if(a1==1||a2==1) return 0; if(a1==-1&&a2==-1) return 1; if(a1==0) { if(SS2==0) { if(Dcross(S2,E1,S1)<=0) return 1; else return 0; } if(EE2==0) { if(Dcross(E2,E1,S1)<=0) return 1; else return 0; } } if(a2==0) { if(SS1==0) { if(Dcross(S1,E2,S2)<=0) return 1; else return 0; } if(EE1==0) { if(Dcross(E1,E2,S2)<=0) return 1; else return 0; } } return 1; } void solve() { for(int i=1;i<=N;i++) for(int j=i+1;j<=N;j++) { if(panX(start[i],end[i],start[j],end[j])) ans++; } } int main() { // init(); while(scanf("%d",&N)!=EOF&&N) { input(); solve(); cout<<ans<<endl; } return 0; }
用胡浩大牛的模板再写一遍
#include <cstdio> #include <cmath> #include <algorithm> #include<iostream> using namespace std; #define M 250 #define INF 0xFFFFFFF const double eps = 1e-8; const double inf = 10000; const int maxP = 1100; const double PI = acos(-1.0); inline double sqr(double d) { return d * d; } inline int sgn(double d) { return d < -eps? -1: d > eps; } struct Point { double x, y; Point(const double &_x = 0, const double &_y = 0) : x(_x), y(_y) {} bool operator == (const Point &p) const { return sgn(x - p.x) == 0 && sgn(y - p.y) == 0; } bool operator < (const Point &p) const { return y + eps < p.y || (y < p.y + eps && x + eps < p.x); } Point operator + (const Point &p) const { return Point(x + p.x, y + p.y); } Point operator - (const Point &p) const { return Point(x - p.x, y - p.y); } Point operator * (const double &k) const { return Point(x * k, y * k); } Point operator / (const double &k) const { return Point(x / k, y / k); } //叉积: <0:p在x的逆时针方向, =0: 共线, >0:顺时针方向 double operator *(const Point &p) const { return x * p.y - y * p.x; } //点积:<0 :钝角, =0 :直角, >0 :锐角 double operator / (const Point &p) const { return x * p.x + y * p.y; } double len2() { return x * x + y * y; } double len() { return sqrt(x * x + y * y); } //向量变化为对应单位向量的k倍 Point scale(const double &k) { return sgn(len())? (*this) * (k / len()): (*this); } //点关于y = x对称, 再关于y轴对称(向量逆时针旋转90度) Point turnLeft() { return Point(-y, x); } //点关于y = x对称, 再关于x轴对称(向量顺时针旋转90度) Point turnRight() { return Point(y, -x); } void input() { scanf("%lf%lf", &x, &y); } void output() { printf("%.2lf %.2lf\n", x + eps, y + eps); } double Distance(Point p) { return sqrt(sqr(p.x - x) + sqr(p.y - y)); } //以点P位轴逆时针转angle角度, 再放大k倍 Point rotate(const Point &p, double angle, double k = 1) { Point vec = (*this) - p; double Cos(cos(angle) * k), Sin(sin(angle) * k); return p + Point(vec.x * Cos - vec.y * Sin, vec.x * Sin + vec.y * Cos); } }; struct Line { Point a , b; Line(const Point &_a = 0, const Point &_b = 0): a(_a), b(_b) {} Line(double c, double d, double e, double f): a(Point(c, d)), b(Point(e, f)) {} //<0: 点p在直线左边, =0: 点p在直线上, >0: 点p在直线右边 double operator * (const Point &p) const { return (b - a) * (p - a); } //>0: 角apb为锐角, =0:角apb为直角, <0: 角apb为钝角 double operator / (const Point &p) const { return (p - a) / (p - b); } void input() { a.input(); b.input(); } void output() { a.output(); b.output(); } double len() { return a.Distance(b); } //是否和直线v共线 bool parallel(Line v) { return !sgn((b - a) * (v.b - v.a)); } //是否和线段v相交, 交点是p bool SegCrossSeg(const Line &v, Point &p) { double s1 = v * a, s2 = v * b; if(sgn(s2 - s1) == 0) return false; p = (a * s2 - b * s1) / (s2 - s1); return (sgn(v / p) <= 0 && sgn((*this) / p) <= 0); } //线段与线段v 2: 规范相交, 1: 不规范相交, 0: 不相交 int SegCrossSeg(const Line &v) { int d1 = sgn((*this) * v.a); int d2 = sgn((*this) * v.b); int d3 = sgn(v * a); int d4 = sgn(v * b); if((d1 ^ d2) == -2 && (d3 ^ d4) == -2) return 2; return ((d1 == 0 && sgn((*this) / v.a) <= 0) || (d2 == 0 && sgn(( *this ) / v.b) <= 0) || (d3 == 0 && sgn(v / a) <= 0) || (d4 == 0 && sgn(v / b) <= 0)); } //直线与线段v 2: 规范相交, 1: 不规范相交, 0: 不相交 int LineCrossSeg(const Line &v) { int d1 = sgn((*this) * v.a) , d2 = sgn((*this) * v.b); if((d1 ^ d2) == -2) return 2; return (d1 == 0 || d2 == 0); } //直线与直线v 2: 规范相交, 1: 重合, 0: 不相交 int LineCrossLine(const Line &v) { if((*this).parallel(v)) return (sgn(v * a) == 0); return 2; } //返回两条直线的交点 Point CrossPoint(const Line &v) { double s1 = v * a , s2 = v * b; return (a * s2 - b * s1) / (s2 - s1); } //返回点p到线段的最短距离 double DisPointToSeg(Point p) { if(a == b) return a.Distance(p); Point q = p + (a - b).turnLeft(); if(((p - a) * (q - a)) * ((p - b) * (q - b)) > 0) return min(p.Distance(a), p.Distance(b)); return fabs((*this) * p) / a.Distance(b); } //返回点p到线段的最短距离的点 Point PointToSeg(Point p) { if(a == b) return a; Point q = p + ( a - b ).turnLeft(); if(((p - a) * (q - a)) * ((p - b) * (q - b)) > 0) return p.Distance(a) < p.Distance(b) ? a : b; return CrossPoint(Line(p, q)); } //返回点P到直线的距离 double DisPointToLine(const Point &p) { return fabs((*this) * p) / a.Distance(b); } //返回过点P与直线垂直的直线的交点 Point PointToLine(const Point &p) { return CrossPoint(Line(p, p + (a - b).turnLeft())); } //返回点Q, 直线PQ平行该直线 Point SymPoint(const Point &p) { return PointToLine(p) * 2 - p; } //向法线方向平移d void Move(const double &d) { Point t = (b - a).turnLeft().scale(d); a = a + t, b = b + t; } }; Line A[101]; int N; int ans; void input() { ans=0; for(int i=1;i<=N;i++) { scanf("%lf%lf%lf%lf",&A[i].a.x,&A[i].a.y,&A[i].b.x,&A[i].b.y); } } void solve() { for(int i=1;i<=N;i++) for(int j=i+1;j<=N;j++) { if(A[i].SegCrossSeg(A[j])) ans++; } } int main() { while(scanf("%d",&N)!=EOF&&N) { input(); solve(); cout<<ans<<endl; } return 0; }