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. 
 
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.
 
Output
For each case, print the number of intersections, and one line one case.
 
Sample Input
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】线段交点的更多相关文章

  1. fzu 1015 土地划分(判断线段相交+求出交点+找规律)

    链接:http://acm.fzu.edu.cn/problem.php?pid=1015  Problem 1015 土地划分 Accept: 714    Submit: 1675Time Lim ...

  2. hdu 1558 (线段相交+并查集) Segment set

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1558 题意是在坐标系中,当输入P(注意是大写,我当开始就wa成了小写)的时候输入一条线段的起点坐标和终点坐 ...

  3. 【计算几何初步-代码好看了点线段相交】【HDU2150】Pipe

    题目没什么 只是线段相交稍微写的好看了点 Pipe Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Jav ...

  4. POJ2284 That Nice Euler Circuit (欧拉公式)(计算几何 线段相交问题)

                                                          That Nice Euler Circuit Time Limit: 3000MS   M ...

  5. POJ 1039 Pipe(直线和线段相交判断,求交点)

    Pipe Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 8280   Accepted: 2483 Description ...

  6. 51Nod 1264 线段相交(计算几何)

    1264 线段相交  基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出平面上两条线段的两个端点,判断这两条线段是否相交(有一个公共点或有部分重合认为相 ...

  7. poj 1127 -- Jack Straws(计算几何判断两线段相交 + 并查集)

    Jack Straws In the game of Jack Straws, a number of plastic or wooden "straws" are dumped ...

  8. 51nod_1264:线段相交(计算几何)

    题目链接 关于判断线段相交,具体算法见 点击打开链接 ,先进行快速排斥试验,若不能判断出两个线段不相交,再进行跨立试验. //吐槽1,long long 会溢出... //吐槽2,只进行跨立试验的虽然 ...

  9. (计算几何 线段判交) 51nod1264 线段相交

    1264 线段相交 给出平面上两条线段的两个端点,判断这两条线段是否相交(有一个公共点或有部分重合认为相交). 如果相交,输出"Yes",否则输出"No".   ...

随机推荐

  1. Android加载图片OOM错误解决方式

    前几天做项目的时候,甲方要求是PAD (SAMSUNG P600 10.1寸 2560*1600)的PAD上显示高分辨率的大图片. SQLITE採用BOLD方式存储图片,这个存取过程就不说了哈,网上一 ...

  2. 根据list<Object>中的某个字段排序

    compareTo必须是两个对象之间的比较(比如Long,Integer...),以下例子是升序排序 private void businessSort(List<WxDailyBusiness ...

  3. [Python学习笔记][第五章Python函数设计与使用]

    2016/1/29学习内容 第四章 Python函数设计与使用 之前的几页忘记保存了 很伤心 变量作用域 -一个变量已在函数外定义,如果在函数内需要修改这个变量的值,并将这个赋值结果反映到函数之外,可 ...

  4. 如何禁用Visual Studio 2013的Browser Link功能

    VS2013新增的Browser Link功能虽然“强大”,但我并不需要. 但默认是开启的,会在页面中自动添加如下的代码,真是烦人! <!-- Visual Studio Browser Lin ...

  5. jBPM4.4与SSH2整合

    整合jBPM的目的就是能够通过注入的方式得到ProcessEngine实例,因为ProcessEngine是jbpm 的核心. 整合步骤: 1.新建web程,搭建好SSH2环境 2.导入jbpm相关的 ...

  6. java之package与import

    我就以package与import开始吧. package的作用其实就是c++的namespace的作用,防止名字相同的类产生冲突,只是实现的机制不一样,java编译器在编译时,直接根据package ...

  7. OFBiz应用https与http方式访问切换

    url.properties port.https.enabled=N port.https=8444 force.https.host=

  8. php 大流量网站访问

    1:确认服务器硬件能否支持当前流量 2:数据库优化,用到什么字段查什么字段,减轻查询负担. 3:静态化,缓存,减少连库操作. 4:禁止外部盗链,减轻负载压力. 5:控制文件下载大小,尽量不超过2M,有 ...

  9. Mysql 建表时,日期时间类型选择

    mysql(5.5)所支持的日期时间类型有:DATETIME. TIMESTAMP.DATE.TIME.YEAR. 几种类型比较如下: 日期时间类型 占用空间 日期格式 最小值 最大值 零值表示  D ...

  10. 用PHP向MySql中写入图片

    我们经常遇到的问题是如何将图片文件放到Mysql数据库当中,这样可以避免没有认证的用户找到我们的图片资源! 1.看看数据库里的表结构怎么写 CREATE TABLE Images (     PicN ...