【计算几何初步-线段相交】【HDU1089】线段交点
来源:互联网 发布:谜一样的双眼知乎 编辑:程序博客网 时间:2024/05/22 00:22
You can Solve a Geometry Problem too
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 7847 Accepted Submission(s): 3834
Problem Description
Many geometry(几何)problems were designed in the ACM/ICPC. And now, I also prepare a geometry problem for this final exam. According to the experience of many ACMers, geometry problems are always much trouble, but this problem is very easy, after all we are now attending an exam, not a contest :)
Give you N (1<=N<=100) segments(线段), please output the number of all intersections(交点). You should count repeatedly if M (M>2) segments intersect at the same point.
Note:
You can assume that two segments would not intersect at more than one point.
Give you N (1<=N<=100) segments(线段), please output the number of all intersections(交点). You should count repeatedly if M (M>2) segments intersect at the same point.
Note:
You can assume that two segments would not intersect at more than one point.
Input
Input contains multiple test cases. Each test case contains a integer N (1=N<=100) in a line first, and then N lines follow. Each line describes one segment with four float values x1, y1, x2, y2 which are coordinates of the segment’s ending.
A test case starting with 0 terminates the input and this test case is not to be processed.
A test case starting with 0 terminates the input and this test case is not to be processed.
Output
For each case, print the number of intersections, and one line one case.
Sample Input
20.00 0.00 1.00 1.000.00 1.00 1.00 0.0030.00 0.00 1.00 1.000.00 1.00 1.00 0.0000.00 0.00 1.00 0.000
求线段相交分为两个讨论
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-6using 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-6using 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 0xFFFFFFFconst 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相交, 交点是pbool 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;}//向法线方向平移dvoid 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;}
0 0
- 【计算几何初步-线段相交】【HDU1089】线段交点
- POJ 1039-Pipe(计算几何-线段相交、求交点)
- 【计算几何】线段相交
- poj1039(计算几何)线段相交
- 【计算几何】判断线段相交
- 计算几何 线段相交 模板
- 计算几何之线段性质(二):求线段交点
- {计算几何}怎样判断线段相交
- 计算几何,判两线段相交模板
- 计算几何之判断线段相交
- poj3304 计算几何 线段与直线相交
- HDU 1086 计算几何 判断线段相交
- 计算几何中的线段相交判断问题
- POJ 2318 TOYS 计算几何 线段相交
- 计算几何之两线段相交
- 哈理工 1559 线段相交【计算几何】
- 计算几何--判断线段是否相交
- 计算几何:线段相交(迷宫寻宝)
- 《unix高级环境编程》高级 I/O—— I/O 多路转接
- Ubuntu系统下Hadoop 2.0.4集群安装配置
- 中科院博士教你如何查找外文文献
- 第十三周项目六:体验文件操作3.0
- 《unix高级环境编程》高级 I/O—— readv 和 writev 函数
- 【计算几何初步-线段相交】【HDU1089】线段交点
- MediaPlayer和AudioTrack播放Audio的区别与联系
- 新旧代码兼容
- python 开始! Python 关于 name main的使用
- JavaFX使用摄像头API的示例
- 进程-IPC 共享内存和消息队列 (三)
- 《unix高级环境编程》高级 I/O—— 存储映射 I/O
- Python中的sorted函数以及operator.itemgetter函数
- 初学lua(转)