【计算几何初步-线段相交】【HDU1089】线段交点
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
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.
A test case starting with 0 terminates the input and this test case is not to be processed.
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;
}
【计算几何初步-线段相交】【HDU1089】线段交点的更多相关文章
- fzu 1015 土地划分(判断线段相交+求出交点+找规律)
链接:http://acm.fzu.edu.cn/problem.php?pid=1015 Problem 1015 土地划分 Accept: 714 Submit: 1675Time Lim ...
- hdu 1558 (线段相交+并查集) Segment set
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1558 题意是在坐标系中,当输入P(注意是大写,我当开始就wa成了小写)的时候输入一条线段的起点坐标和终点坐 ...
- 【计算几何初步-代码好看了点线段相交】【HDU2150】Pipe
题目没什么 只是线段相交稍微写的好看了点 Pipe Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Jav ...
- POJ2284 That Nice Euler Circuit (欧拉公式)(计算几何 线段相交问题)
That Nice Euler Circuit Time Limit: 3000MS M ...
- POJ 1039 Pipe(直线和线段相交判断,求交点)
Pipe Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 8280 Accepted: 2483 Description ...
- 51Nod 1264 线段相交(计算几何)
1264 线段相交 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出平面上两条线段的两个端点,判断这两条线段是否相交(有一个公共点或有部分重合认为相 ...
- poj 1127 -- Jack Straws(计算几何判断两线段相交 + 并查集)
Jack Straws In the game of Jack Straws, a number of plastic or wooden "straws" are dumped ...
- 51nod_1264:线段相交(计算几何)
题目链接 关于判断线段相交,具体算法见 点击打开链接 ,先进行快速排斥试验,若不能判断出两个线段不相交,再进行跨立试验. //吐槽1,long long 会溢出... //吐槽2,只进行跨立试验的虽然 ...
- (计算几何 线段判交) 51nod1264 线段相交
1264 线段相交 给出平面上两条线段的两个端点,判断这两条线段是否相交(有一个公共点或有部分重合认为相交). 如果相交,输出"Yes",否则输出"No". ...
随机推荐
- Afianl加载网络图片(延续)
上一页"已经谈到了如何使用Afianl网络负载的图片和下载文件,本文将继续介绍使用Afinal使用网络负载图片,主绑定listview采用: 看效果图: listview在滑动过程中没用明显 ...
- Ext的labelWidth默认会给100
Ext的textfield控件的labelWidth属性,如果没有设置这个属性,那么默认会给100,导致左侧有100px的留白
- OD调试2---TraceMe
OD调试2---TraceMe 拆解一个Windows程序要比拆解一个DOS程序容易得多,因为在Windows中,只要API函数被使用,想对寻找蛛丝马迹的人隐藏一些东西是比较困难的.因此分析一个程序, ...
- hdu120118岁生日
Problem Description Gardon的18岁生日就要到了,他当然很开心,可是他突然想到一个问题,是不是每个人从出生开始,到达18岁生日时所经过的天数都是一样的呢?似乎并不全都是这样,所 ...
- BlockingQueue
BlockingQueue的使用 http://www.cnblogs.com/liuling/p/2013-8-20-01.html BlockingQueue深入分析 http://blog.cs ...
- Qt Library 链接库
官方教程:http://wiki.qt.io/How_to_create_a_library_with_Qt_and_use_it_in_an_application http://qimo601.i ...
- js经典代码技巧学习之一:使用三元运算符处理javascript兼容
window.Event = { add: function() { //使用条件表达式检测标准方法是否存在 return document.addEventListener ? function(a ...
- Eloquent ORM 学习笔记
最近在学习Laravel,觉得ORM功能很强大,我这里只是简单探索了一点,如果有更好的笔记,还请分享. 因为重点在于Eloquent ORM,所以路由设置,控制器就不详细描述了,这里直接进入Model ...
- HDU ACM 题目分类
模拟题, 枚举1002 1004 1013 1015 1017 1020 1022 1029 1031 1033 1034 1035 1036 1037 1039 1042 1047 1048 104 ...
- H.数7(模拟)
1212: H.数7 时间限制: 1 Sec 内存限制: 64 MB 提交: 8 解决: 5 标签提交统计讨论版 题目描述 数7是一个简单的饭桌游戏,有很多人围成一桌,先从任意一人开始数数,1.2 ...