题解
题意的交点可以理解为两种 1常规相交如X形 2交点不是都是两个线段的端点如T形和…__…下划线表示重叠位置
直接套计算几何模版(以下代码使用kuangbin大大的计算几何模版直接复制粘贴无删减篇幅过长233)
判断交点是否常规相交 非常规相交判断一个线段的端点在另一个线段上要求这个端点不能等于另一个线段的两个端点
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 2e3 + 10;
const double pi = acos(-1.0);
int sgn(double x){
if (fabs(x) < 1e-11)return 0;
if (x < 0)return -1;
else return 1;
}
struct Point{
double x, y;
Point(){}
Point(double _x, double _y){
x = _x;
y = _y;
}
void input(){
scanf("%lf%lf", &x, &y);
}
void output(){
printf("%.2f␣%.2f\n", x, y);
}
bool operator == (Point b)const{
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator < (Point b)const{
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator - (const Point &b)const{
return Point(x - b.x, y - b.y);
}
//叉积
double operator ^(const Point &b)const{
return x*b.y - y*b.x;
}
//点积
double operator *(const Point &b)const{
return x*b.x + y*b.y;
}
//返回长度
double len(){
return hypot(x, y);//库函数
}
//返回长度的平方
double len2(){
return x*x + y*y;
}
//返回两点的距离
double distance(Point p){
return hypot(x - p.x, y - p.y);
}
Point operator +(const Point &b)const{
return Point(x + b.x, y + b.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);
}
//计算 pa 和 pb 的夹角
//就是求这个点看 a,b 所成的夹角
//测试 LightOJ1203
double rad(Point a, Point b){
Point p = *this;
return fabs(atan2(fabs((a - p) ^ (b - p)), (a - p)*(b - p)));
}
//化为长度为 r 的向量
Point trunc(double r){
double l = len();
if (!sgn(l))return *this;
r /= l;
return Point(x*r, y*r);
}
//逆时针旋转 90 度
Point rotleft(){
return Point(- y, x);
}
//顺时针旋转 90 度
Point rotright(){
return Point(y, - x);
}
//绕着 p 点逆时针旋转 angle
Point rotate(Point p, double angle){
Point v = (*this) - p;
double c = cos(angle), s = sin(angle);
return Point(p.x + v.x*c - v.y*s, p.y + v.x*s + v.y*c);
}
};
struct Line{
Point s, e;
Line(){}
Line(Point _s, Point _e){
s = _s;
e = _e;
}
bool operator ==(Line v){
return (s == v.s) && (e == v.e);
}
//根据一个点和倾斜角 angle 确定直线,0<=angle<pi
Line(Point p, double angle){
s = p;
if (sgn(angle - pi / 2) == 0){
e = (s + Point(0, 1));
}
else{
e = (s + Point(1, tan(angle)));
}
}
//ax+by+c=0
Line(double a, double b, double c){
if (sgn(a) == 0){
s = Point(0, - c / b);
e = Point(1, - c / b);
}
else if (sgn(b) == 0){
s = Point(- c / a, 0);
e = Point(- c / a, 1);
}
else{
s = Point(0, - c / b);
e = Point(1, (- c - a) / b);
}
}
void input(){
s.input();
e.input();
}
void adjust(){
if (e < s)swap(s, e);
}
//求线段长度
double length(){
return s.distance(e);
}
//返回直线倾斜角 0<=angle<pi
double angle(){
double k = atan2(e.y - s.y, e.x - s.x);
if (sgn(k) < 0)k += pi;
if (sgn(k - pi) == 0)k -= pi;
return k;
}
//点和直线关系
//1 在左侧
//2 在右侧
//3 在直线上
int relation(Point p){
int c = sgn((p - s) ^ (e - s));
if (c < 0)return 1;
else if (c > 0)return 2;
else return 3;
}
// 点在线段上的判断
bool pointonseg(Point p){
return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s)*(p - e)) <= 0;
}
//两向量平行 (对应直线平行或重合)
bool parallel(Line v){
return sgn((e - s) ^ (v.e - v.s)) == 0;
}
//两线段相交判断
//2 规范相交
//1 非规范相交
//0 不相交
int segcrossseg(Line v){
int d1 = sgn((e - s) ^ (v.s - s));
int d2 = sgn((e - s) ^ (v.e - s));
int d3 = sgn((v.e - v.s) ^ (s - v.s));
int d4 = sgn((v.e - v.s) ^ (e - v.s));
if ((d1^d2) == - 2 && (d3^d4) == - 2)return 2;
return (d1 == 0 && sgn((v.s - s)*(v.s - e)) <= 0) ||
(d2 == 0 && sgn((v.e - s)*(v.e - e)) <= 0) ||
(d3 == 0 && sgn((s - v.s)*(s - v.e)) <= 0) ||
(d4 == 0 && sgn((e - v.s)*(e - v.e)) <= 0);
}
//直线和线段相交判断
//-*this line -v seg
//2 规范相交
//1 非规范相交
//0 不相交
int linecrossseg(Line v){
int d1 = sgn((e - s) ^ (v.s - s));
int d2 = sgn((e - s) ^ (v.e - s));
if ((d1^d2) == - 2) return 2;
return (d1 == 0 || d2 == 0);
}
//两直线关系
//0 平行
//1 重合
//2 相交
int linecrossline(Line v){
if ((*this).parallel(v))
return v.relation(s) == 3;
return 2;
}
//求两直线的交点
//要保证两直线不平行或重合
Point crosspoint(Line v){
double a1 = (v.e - v.s) ^ (s - v.s);
double a2 = (v.e - v.s) ^ (e - v.s);
return Point((s.x*a2 - e.x*a1) / (a2 - a1), (s.y*a2 - e.y*a1) / (a2 - a1));
}
//点到直线的距离
double dispointtoline(Point p){
return fabs((p - s) ^ (e - s)) / length();
}
//点到线段的距离
double dispointtoseg(Point p){
if (sgn((p - s)*(e - s)) < 0 || sgn((p - e)*(s - e)) < 0)
return min(p.distance(s), p.distance(e));
return dispointtoline(p);
}
//返回线段到线段的距离
//前提是两线段不相交,相交距离就是 0 了
double dissegtoseg(Line v){
return min(min(dispointtoseg(v.s), dispointtoseg(v.e)), min(v
.dispointtoseg(s), v.dispointtoseg(e)));
}
//返回点 p 在直线上的投影
Point lineprog(Point p){
return s + (((e - s)*((e - s)*(p - s))) / ((e - s).len2()));
}
//返回点 p 关于直线的对称点
Point symmetrypoint(Point p){
Point q = lineprog(p);
return Point(2 * q.x - p.x, 2 * q.y - p.y);
}
};
Point p[MAXN];
Line l[MAXN];
int g[MAXN][MAXN];
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
g[u][v] = 1;
}
for (int i = 1; i <= n; i++)
{
int x, y;
scanf("%d%d", &x, &y);
p[i] = Point(x, y);
}
int pos = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (g[i][j])
l[++pos] = Line(p[i], p[j]);
int ans = 0;
for (int i = 1; i <= m; i++)
for (int j = i + 1; j <= m; j++)
if (l[i].segcrossseg(l[j]) == 2) //X形
ans++;
else if (l[i].pointonseg(l[j].s) && !(l[i].s == l[j].s) && !(l[i].e == l[j].s) || //一个边的点在另一个边上有交点且不是端点
l[i].pointonseg(l[j].e) && !(l[i].s == l[j].e) && !(l[i].e == l[j].e) ||
l[j].pointonseg(l[i].s) && !(l[j].s == l[i].s) && !(l[j].e == l[i].s) ||
l[j].pointonseg(l[i].e) && !(l[j].s == l[i].e) && !(l[j].e == l[i].e))
ans++;
cout << ans << endl;
return 0;
}