您的位置:首页 > 理论基础 > 计算机网络

2017 ACM-ICPC 亚洲区(南宁赛区)网络赛 I.GSM Base Station Identification

2017-10-07 16:44 531 查看
题目链接:https://nanti.jisuanke.com/t/17316

题目大意:给出点的坐标,判断该点在哪个正六边形内

解题思路:把每个正六边形中心映射成真实的坐标中心,然后找出六个顶点,再套模板判断点是否在多边形内部

AC代码:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
using namespace std;

const int MAXN = 200000 + 5;
const double PI = acos(-1.0);
const double EPS = 1e-12;
const int INF = 0x3f3f3f3f;

double antiR;//反演圆半径
int stack[MAXN], top;

int judgeZero(double a)//a>0为1,<0为-1,=0为0
{
return (a > EPS) - (a < -EPS);
}

struct Point
{
double _x, _y;
Point(double x = 0.0, double y = 0.0) :_x(x), _y(y) {}
Point(const Point& p) { _x = p._x, _y = p._y; }
bool operator<(const Point& p)const
{
if (judgeZero(_x - p._x) != 0) return _x < p._x;
return _y < p._y;
}
bool operator==(const Point& p)const
{
return judgeZero(_x - p._x) == 0 && judgeZero(_y - p._y) == 0;
}
void toMove(Point a, double rad, double d)
4000

{
_x = a._x + cos(rad)*d;
_y = a._y + sin(rad)*d;
}
Point operator+(Point a) { return Point(_x + a._x, _y + a._y); }
Point operator-(Point a) { return Point(_x - a._x, _y - a._y); }
friend Point operator*(double a, Point p) { return Point(a*p._x, a*p._y); }
friend istream& operator >> (istream& in, Point& point)
{
in >> point._x >> point._y;
return in;
}
friend ostream& operator<<(ostream& out, const Point& point)
{
out << fixed << setprecision(8) << point._x << ' ' << point._y;
return out;
}
}crossp[MAXN], polygon[MAXN];

double getDis(Point a, Point b)
{
return sqrt((a._x - b._x)*(a._x - b._x) + (a._y - b._y)*(a._y - b._y));
}

typedef vector<Point> Polygon;

struct Circle
{
Point _o;
double _r;
Circle(double x = 0.0, double y = 0.0, double r = 0.0) :_o(x, y), _r(r) {}
Circle(const Point& o, double r) :_o(o), _r(r) {}
Circle antiCircle(const Point& point)
{
Circle antic;
double dis = getDis(point, _o);
double tmp = antiR*antiR / (dis*dis - _r*_r);
antic._r = tmp*_r;
antic._o._x = point._x + tmp*(_o._x - point._x);
antic._o._y = point._y + tmp*(_o._y - point._y);
return antic;
}
friend istream& operator >> (istream& in, Circle& circle)
{
in >> circle._o >> circle._r;
return in;
}
friend ostream& operator<<(ostream& out, const Circle& circle)
{
out << circle._o << ' ' << circle._r;
return out;
}
};

double getCross(Point p1, Point p2, Point p)
{
return (p1._x - p._x)*(p2._y - p._y) - (p2._x - p._x)*(p1._y - p._y);
}

double getMulti(Point p1, Point p2, Point p)
{
return (p1._x - p._x)*(p2._x - p._x) + (p1._y - p._y)*(p2._y - p._y);
}

bool onSegment(Point p, Point a, Point b)//点p与线段ab
{
if (judgeZero(getCross(a, b, p)) != 0)
return false;
if (p._x<min(a._x, b._x) || p._x>max(a._x, b._x))//trick:垂直或平行坐标轴;
return false;
if (p._y<min(a._y, b._y) || p._y>max(a._y, b._y))
return false;
return true;
}

bool segmentIntersect(Point a, Point b, Point c, Point d)//线段ab与线段cd
{
if (onSegment(c, a, b) || onSegment(d, a, b) || onSegment(a, c, d) || onSegment(b, c, d))
return true;
if (judgeZero(getCross(a, b, c)*getCross(a, b, d)) < 0 && judgeZero(getCross(c, d, a)*getCross(c, d, b)) < 0)//==0的特殊情况已经在前面排除
return true;
return false;
}

bool onLine(Point p, Point a, Point b)//点p与直线ab
{
return judgeZero(getCross(a, b, p)) == 0;
}

bool lineIntersect(Point a, Point b, Point c, Point d)//直线ab与直线cd
{
if (judgeZero((a._x - b._x)*(c._y - d._y) - (c._x - d._x)*(a._y - b._y)) != 0)
return true;
if (onLine(a, c, d))//两直线重合
return true;
return false;
}

bool segment_intersectLine(Point a, Point b, Point c, Point d)//线段ab与直线cd
{
if (judgeZero(getCross(c, d, a)*getCross(c, d, b)) <= 0)
return true;
return false;
}

Point point_line_intersectLine(Point p1, Point p2, Point p3, Point p4)//求出交点,直线(线段)p1p2与直线(线段)p3p4
{//t=lamta/(lamta+1),必须用t取代lamta,不然算lamta可能分母为0
double x1 = p1._x, y1 = p1._y;
double x2 = p2._x, y2 = p2._y;
double x3 = p3._x, y3 = p3._y;
double x4 = p4._x, y4 = p4._y;
double t = ((x2 - x1)*(y3 - y1) - (x3 - x1)*(y2 - y1)) / ((x2 - x1)*(y3 - y4) - (x3 - x4)*(y2 - y1));
return Point(x3 + t*(x4 - x3), y3 + t*(y4 - y3));
}

bool inPolygon(Point a, Polygon polygon)//点是否含于多边形
{
Point b(-1e15 + a._x, a._y);//向左无穷远的线段
int count = 0;
for (int i = 0;i < polygon.size();++i)
{
Point c = polygon[i], d = polygon[(i + 1) % polygon.size()];
if (onSegment(a, c, d)) //如果点在线段上,那么一定在多边形内
return true;
if (judgeZero((a._x - b._x)*(c._y - d._y) - (c._x - d._x)*(a._y - b._y)) == 0)
continue;//如果边与射线平行,trick1
if (!segmentIntersect(a, b, c, d))
continue;//如果边与射线没有交点
Point lower;
if (c._y < d._y) lower = c;
else lower = d;
if (onSegment(lower, a, b)) //如果纵坐标小的点与射线有交点,trick2
continue;
count++;
}
return count % 2 == 1;
}

bool inPolygon(Point a, Point polygon[], int n)
{
Point b(-1e15 + a._x, a._y);
int count = 0;
for (int i = 0;i < n;++i)
{
Point c = polygon[i], d = polygon[(i + 1) % n];
if (onSegment(a, c, d))
return true;
if (judgeZero((a._x - b._x)*(c._y - d._y) - (c._x - d._x)*(a._y - b._y)) == 0)
continue;
if (!segmentIntersect(a, b, c, d))
continue;
Point lower;
if (c._y < d._y) lower = c;
else lower = d;
if (onSegment(lower, a, b))
continue;
count++;
}
return count % 2 == 1;
}

bool segment_inPolygon(Point a, Point b, Polygon polygon)//线段是否含于多边形
{
if (!inPolygon(a, polygon) || !inPolygon(b, polygon))//两个端点都不在多边形内
return false;
int tot = 0;
for (int i = 0;i < polygon.size();++i)
{
Point c = polygon[i], d = polygon[(i + 1) % polygon.size()];
if (onSegment(a, c, d))//以下只用记录一个交点,多的要么重复,要么一定在边上
crossp[tot++] = a;
else if (onSegment(b, c, d))
crossp[tot++] = b;
else if (onSegment(c, a, b))
crossp[tot++] = c;
else if (onSegment(d, a, b))
crossp[tot++] = d;
else if (segmentIntersect(a, b, c, d))//端点没有在线段上且相交
return false;
}
sort(crossp, crossp + tot);//按x,y排序
tot = unique(crossp, crossp + tot) - crossp;
for (int i = 0;i < tot - 1;++i)
{
Point tmp = 0.5*(crossp[i] + crossp[i + 1]);
if (!inPolygon(tmp, polygon))//中点不在多边形内
return false;
}
return true;
}

double lineDis_inPolygon(Point a, Point b, Polygon polygon)//求出直线在多边形内的长度
{
int tot = 0;
for (int i = 0;i < polygon.size();++i)
{
Point c = polygon[i], d = polygon[(i + 1) % polygon.size()];
if (onLine(c, a, b) && onLine(d, a, b))//如果边与直线重合,记录两个端点
{
crossp[tot++] = c;
crossp[tot++] = d;
}
else if (segment_intersectLine(c, d, a, b))
crossp[tot++] = point_line_intersectLine(a, b, c, d);
}
sort(crossp, crossp + tot);
tot = unique(crossp, crossp + tot) - crossp;
double ans = 0.0;
for (int i = 0;i < tot - 1;++i)
{
Point tmp = 0.5*(crossp[i] + crossp[i + 1]);
if (inPolygon(tmp, polygon))
ans += getDis(crossp[i], crossp[i + 1]);
}
return ans;
}

bool inCircle(Point p, Circle a)//点是否在圆内
{
return judgeZero(getDis(p, a._o) - a._r) <= 0;
}

double dis_toSegment(Point c, Point a, Point b)//点到线段的最短距离
{
if (judgeZero(getDis(a, b)) == 0) return getDis(c, a);
if (judgeZero(getMulti(a, c, b)) < 0) return getDis(c, b);
if (judgeZero(getMulti(b, c, a)) < 0) return getDis(c, a);
return fabs(getCross(a, b, c)) / getDis(a, b);
}

double dis_segment_toSegment(Point a, Point b, Point c, Point d)//线段到线段的距离
{
double ans1 = min(dis_toSegment(c, a, b), dis_toSegment(d, a, b));
double ans2 = min(dis_toSegment(a, c, d), dis_toSegment(b, c, d));
return min(ans1, ans2);
}

Polygon dividePolygon(Polygon p, Point a, Point b)//直线ab划分多边形
{
int n = p.size();
Polygon newp;
for (int i = 0;i < n;i++)
{
Point c = p[i], d = p[(i + 1) % n];
if (judgeZero(getCross(b, c, a)) > 0)//只记录向量ab左侧的多边形
newp.push_back(c);
if (onLine(c, a, b))//防止重复记录点
newp.push_back(c);
else if (onLine(d, a, b))
continue;
else if (lineIntersect(a, b, c, d))
{
Point tmp = point_line_intersectLine(a, b, c, d);
if (onSegment(tmp, c, d))
newp.push_back(tmp);
}
}
return newp;//要判断newp.size()>=3
}

double polygonArea(Polygon polygon)//多边形面积
{
double ans = 0.0;
for (int i = 1;i < polygon.size() - 1;i++)
ans += getCross(polygon[i], polygon[i + 1], polygon[0]);
return fabs(ans) / 2.0;
}

bool circle_inPolygon(Circle c, Polygon p)//圆含于多边形
{
if (!inPolygon(c._o, p))
return false;
for (int i = 0;i < p.size();i++)
{
Point a = p[i], b = p[(i + 1) % p.size()];
if (judgeZero(dis_toSegment(c._o, a, b) - c._r) < 0)
return false;
}
return true;
}

bool circle_inPolygon(Circle c, Point p[], int n)//圆含于多边形
{
if (!inPolygon(c._o, p, n))
return false;
for (int i = 0;i < n;i++)
{
Point a = p[i], b = p[(i + 1) % n];
if (judgeZero(dis_toSegment(c._o, a, b) - c._r) < 0)
return false;
}
return true;
}

bool polygon_inCircle(Circle c, Polygon p)//多边形含于圆
{
for (int i = 0;i < p.size();i++)
if (!inCircle(p[i], c))
return false;
return true;
}

bool polygon_intersectCircle(Circle c, Polygon p)//圆含于多边形,多边形含于圆,圆和多边形相交,相切没算进去
{
if (polygon_inCircle(c, p) || circle_inPolygon(c, p))
return true;
for (int i = 0;i < p.size();i++)
{
Point a = p[i], b = p[(i + 1) % p.size()];
if (judgeZero(dis_toSegment(c._o, a, b) - c._r) < 0)//算相切要<=0
return true;
}
return false;
}

int point_line_intersectCircle(Circle c, Point a, Point b, Point p[])//线段ab与圆c的交点
{
double A = (b._x - a._x)*(b._x - a._x) + (b._y - a._y)*(b._y - a._y);
double B = 2.0 * ((b._x - a._x)*(a._x - c._o._x) + (b._y - a._y)*(a._y - c._o._y));
double C = (a._x - c._o._x)*(a._x - c._o._x) + (a._y - c._o._y)*(a._y - c._o._y) - c._r*c._r;
double deta = B*B - 4.0 * A*C;
if (judgeZero(deta) < 0) return 0;
double t1 = (-B - sqrt(deta)) / (2.0 * A);
double t2 = (-B + sqrt(deta)) / (2.0 * A);
int tot = 0;
if (judgeZero(t1) >= 0 && judgeZero(1 - t1) >= 0)
p[tot++] = Point(a._x + t1*(b._x - a._x), a._y + t1*(b._y - a._y));
if (judgeZero(t2) >= 0 && judgeZero(1 - t2) >= 0)
p[tot++] = Point(a._x + t2*(b._x - a._x), a._y + t2*(b._y - a._y));
if (tot == 2 && p[0] == p[1]) return 1;
return tot;
}

double sectorArea(Circle c, Point p1, Point p2)//扇形面积op1p2
{
Point op1 = p1 - c._o, op2 = p2 - c._o;
double sita = atan2(op2._y, op2._x) - atan2(op1._y, op1._x);
while (judgeZero(sita) <= 0) sita += 2 * PI;
while (judgeZero(sita - 2 * PI) > 0) sita -= 2 * PI;
sita = min(sita, 2 * PI - sita);
return c._r*c._r*sita / 2.0;
}

double area_triangle_fromCircle(Circle c, Point a, Point b)//圆点,a,b构成的三角形与圆相交的面积
{
bool flag1 = inCircle(a, c);
bool flag2 = inCircle(b, c);
if (flag1 && flag2)//两点在圆内
return fabs(getCross(a, b, c._o) / 2.0);
Point p[2];
int tot = point_line_intersectCircle(c, a, b, p);
if (flag1) return fabs(getCross(a, p[0], c._o) / 2.0) + sectorArea(c, p[0], b);
if (flag2) return fabs(getCross(b, p[0], c._o) / 2.0) + sectorArea(c, p[0], a);
if (tot == 2) return sectorArea(c, p[0], a) + sectorArea(c, p[1], b) + fabs(getCross(p[0], p[1], c._o)) / 2;
return sectorArea(c, a, b);
}

double area_polygon_intersectCircle(Circle c, Polygon p)//多边形和圆的相交面积
{
double ans = 0.0;
for (int i = 0;i < p.size();i++)//trick:只需每相邻的点与圆心相连求相交面积,有向面积可以相互抵消
{
Point a, b;
a = p[i], b = p[(i + 1) % p.size()];
int flag = judgeZero(getCross(a, b, c._o));
ans += flag*area_triangle_fromCircle(c, a, b);
}
return fabs(ans);
}

Point geometryCenter(Polygon p)//几何中心
{
double x = 0.0, y = 0.0;
for (int i = 0;i < p.size();++i)
x += p[i]._x, y += p[i]._y;
return Point(x / p.size(), y / p.size());
}

double area_circle_intersectCircle(Circle c1, Circle c2)//圆相交面积
{
double dis = getDis(c1._o, c2._o);
if (judgeZero(dis - c1._r - c2._r) >= 0)
return 0.0;
else if (judgeZero(fabs(c2._r - c1._r) - dis) >= 0)
return PI*min(c1._r*c1._r, c2._r*c2._r);
double sita1 = acos((c1._r*c1._r + dis*dis - c2._r*c2._r) / 2.0 / c1._r / dis);
double sita2 = acos((c2._r*c2._r + dis*dis - c1._r*c1._r) / 2.0 / c2._r / dis);
return c1._r*c1._r*sita1 + c2._r*c2._r*sita2 - dis*sin(sita1)*c1._r;
}

Circle getCircumcircle(Point p1, Point p2, Point p3)//三角形外接圆
{
double u1 = (p2._x*p2._x - p1._x*p1._x + p2._y*p2._y - p1._y*p1._y) / 2;
double u2 = (p3._x*p3._x - p1._x*p1._x + p3._y*p3._y - p1._y*p1._y) / 2;
double d11 = p2._x - p1._x;
double d12 = p2._y - p1._y;
double d21 = p3._x - p1._x;
double d22 = p3._y - p1._y;
Circle ans;
ans._o = Point((u1*d22 - u2*d12) / (d11*d22 - d21*d12), (u2*d11 - u1*d21) / (d11*d22 - d21*d12));
ans._r = sqrt((ans._o._x - p1._x)*(ans._o._x - p1._x) + (ans._o._y - p1._y)*(ans._o._y - p1._y));
return ans;
}

bool myCmp(Point a, Point b)
{
int flag = judgeZero(getCross(a, b, polygon[0]));
if (flag > 0) return true;
if (flag == 0 && judgeZero(getDis(a, polygon[0] - getDis(b, polygon[0]))) < 0)
return true;
return false;
}

int toGraham(Point polygon[], int n)//求凸包
{
if (n == 1)
{
stack[0] = 0;
return 1;
}
int pos = 0;
for (int i = 1;i < n;++i)
{
if (polygon[pos]._y > polygon[i]._y)
pos = i;
else if (polygon[pos]._y == polygon[i]._y&&polygon[pos]._x > polygon[i]._x)
pos = i;
}
swap(polygon[0], polygon[pos]);
sort(polygon + 1, polygon + n, myCmp);
int top = 2;
stack[0] = 0, stack[1] = 1;
for (int i = 2;i < n;i++)
{
while (top&&judgeZero(getCross(polygon[i], polygon[stack[top - 2]], polygon[stack[top - 1]])) <= 0) top--;//同一条直线上的点不删除的话,改成<
stack[top++] = i;
}
return top;
}

double  grahamDiameter(Point p[], int n)//凸包直径
{
double mxx = 0;
int t = 1;
for (int i = 0;i < n;i++)
{
while (judgeZero(fabs(getCross(p[t], p[(i + 1) % n], p[i])) - fabs(getCross(p[(t + 1) % n], p[(i + 1) % n], p[i]))) < 0)
t = (t + 1) % n;
mxx = max(mxx, getDis(p[(i + 1) % n], p[(t + 1) % n]));
mxx = max(mxx, getDis(p[i], p[t]));
}
return mxx;
}

double minDis_betweenGraham(Point p1[],int numb1,Point p2[],int numb2)//求两个凸包的最短路径
{
int ymin = 0, ymax = 0;
for (int i = 1;i < numb1;i++)
if (p1[i]._y < p1[ymin]._y)
ymin = i;
for (int i = 1;i < numb2;i++)
if (p2[i]._y > p2[ymax]._y)
ymax = i;
double ans = 1e38;
for (int i = 0;i < numb1;i++)
{
double tmp1 = getCross(p1[ymin], p1[(ymin + 1) % numb1], p2[ymax]);
double tmp2 = getCross(p1[ymin], p1[(ymin + 1) % numb1], p2[(ymax + 1) % numb2]);
while (judgeZero(tmp1 - tmp2) < 0)
{
ymax = (ymax + 1) % numb2;
tmp1 = getCross(p1[ymin], p1[(ymin + 1) % numb1], p2[ymax]);
tmp2 = getCross(p1[ymin], p1[(ymin + 1) % numb1], p2[(ymax + 1) % numb2]);
}
ans = min(ans, dis_segment_toSegment(p2[ymax], p2[(ymax + 1) % numb2], p1[ymin], p1[(ymin + 1) % numb1]));
ymin = (ymin + 1) % numb1;
}
return ans;
}

void toJudge(Point a, int& ansi, int& ansj)
{
for (int i = -9;i <= 10;i++)
for (int j = -9;j <= 10;j++)
{
double x1 = sqrt(3)*(2.5*j + 5 * i);
double y1 = 7.5*j;
Polygon p;
p.push_back(Point(x1 - 2.5*sqrt(3), y1 + 2.5));
p.push_back(Point(x1, y1 + 5));
p.push_back(Point(x1 + 2.5*sqrt(3), y1 + 2.5));
p.push_back(Point(x1 + 2.5*sqrt(3), y1 - 2.5));
p.push_back(Point(x1, y1 - 5));
p.push_back(Point(x1 - 2.5*sqrt(3), y1 - 2.5));
if (inPolygon(a, p))
{
ansi = i, ansj = j;
return;
}
}
}

int main()
{
for (int i = 1;i <= 10;i++)
{
int x, y,posi,posj;
scanf("%d%d", &x, &y);
toJudge(Point(x, y), posi, posj);
if (i != 1) printf(", ");
printf("[%d,%d]", posi, posj);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐