2017ICPC北京现场赛G Liaoning Ship’s Voyage(BFS+点在多边形内判定)

题目链接:https://cn.vjudge.net/problem/HihoCoder-1633

题意:有一个nxn的海域,海域上有两类点,一种是点,一种是#,#不可以走,还有给你三个顶点坐标(可能是小数),表示百慕大三角,百慕大三角上的边和顶点可以走,里面不能走,小船可以走8个方向,上下左右,还有四个角,问从左下角走到右上角的最小步数。

题解:普通的一个跑图,加一点几何,我们发现,如果某一时刻穿过百慕大三角,那么一定存在从起点到终点上的某些点在三角形内,那么只要枚举线段上的100个点,判断其是否在三角形内就行啦。

代码:

# define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize(2)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#define inf 0x3f3f3f3f
#define Pair pair<int,int>
//#define int long long
#define fir first
#define sec second

namespace fastIO {
#define BUF_SIZE 100000
#define OUT_SIZE 100000
  //fread->read
  bool IOerror = 0;
  //inline char nc(){char ch=getchar();if(ch==-1)IOerror=1;return ch;}
  inline char nc() {
    static char buf[BUF_SIZE], * p1 = buf + BUF_SIZE, * pend = buf + BUF_SIZE;
    if (p1 == pend) {
      p1 = buf; pend = buf + fread(buf, 1, BUF_SIZE, stdin);
      if (pend == p1) { IOerror = 1; return -1; }
    }
    return *p1++;
  }
  inline bool blank(char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; }
  template<class T> inline bool read(T& x) {
    bool sign = 0; char ch = nc(); x = 0;
    for (; blank(ch); ch = nc());
    if (IOerror)return false;
    if (ch == '-')sign = 1, ch = nc();
    for (; ch >= '0' && ch <= '9'; ch = nc())x = x * 10 + ch - '0';
    if (sign)x = -x;
    return true;
  }
  inline bool read(double& x) {
    bool sign = 0; char ch = nc(); x = 0;
    for (; blank(ch); ch = nc());
    if (IOerror)return false;
    if (ch == '-')sign = 1, ch = nc();
    for (; ch >= '0' && ch <= '9'; ch = nc())x = x * 10 + ch - '0';
    if (ch == '.') { double tmp = 1; ch = nc(); for (; ch >= '0' && ch <= '9'; ch = nc())tmp /= 10.0, x += tmp * (ch - '0'); }
    if (sign)x = -x; return true;
  }
  inline bool read(char* s) {
    char ch = nc();
    for (; blank(ch); ch = nc());
    if (IOerror)return false;
    for (; !blank(ch) && !IOerror; ch = nc())* s++ = ch;
    *s = 0;
    return true;
  }
  inline bool read(char& c) {
    for (c = nc(); blank(c); c = nc());
    if (IOerror) { c = -1; return false; }
    return true;
  }
  template<class T, class... U>bool read(T& h, U& ... t) { return read(h) && read(t...); }
#undef OUT_SIZE
#undef BUF_SIZE
};
using namespace fastIO;
using namespace std;


/*---------------------------------------------------------------------------------------------------------------------------*/
const double eps = 1e-10;
struct Point { double x, y; Point(double x = 0, double y = 0) :x(x), y(y) {} };
typedef Point Vector;
Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }
Vector operator - (Point A, Point B) { return Vector(A.x - B.x, A.y - B.y); }
Vector operator * (Vector A, double p) { return Vector(A.x * p, A.y * p); }
Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y / p); }
bool operator < (const Point& A, const Point& B) { return A.x < B.x || (A.x == B.x && A.y < B.y); }
int dcmp(double x) { if (fabs(x) < eps)return 0; else return x < 0 ? -1 : 1; }
bool operator == (const Point& A, const Point& B) { return dcmp(A.x - B.x) == 0 && dcmp(A.y - B.y) == 0; }
double Dot(Vector A, Vector B) { return A.x * B.x + A.y * B.y; }
double Length(Vector A) { return sqrt(Dot(A, A)); }
double Dist2(const Point& A, const Point& B) { return (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y); }
double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); }
double Cross(Vector A, Vector B) { return A.x * B.y - A.y * B.x; }
double Area2(Point A, Point B, Point C) { return Cross(B - A, C - A); }
double DistanceToLine(Point P, Point A, Point B) { Vector v1 = B - A, v2 = P - A; return fabs(Cross(v1, v2)) / Length(v1); }
Vector Normal(Vector A) { double L = Length(A); return Vector(-A.y / L, A.x / L); }
Vector Rotate(Vector A, double rad) { return Vector(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad)); }
Point GetLineIntersection(Point P, Vector v, Point Q, Vector w) { Vector u = P - Q; double t = Cross(w, u) / Cross(v, w); return P + v * t; }
double PolygonArea(vector<Point>p) {//duo area
  double area = 0;
  int n = p.size();
  for (int i = 1; i < n - 1; i++)area += Cross(p[i] - p[0], p[i + 1] - p[0]);
  return area / 2;
}
double torad(double deg) { return deg / 180 * acos(-1); }
vector<Point> ConvexHull(vector<Point>& p) {
  sort(p.begin(), p.end());
  p.erase(unique(p.begin(), p.end()), p.end());
  int n = p.size();
  int m = 0;
  vector<Point> ch(n + 1);
  for (int i = 0; i < n; i++) { while (m > 1 && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= 0)m--; ch[m++] = p[i]; }
  int k = m;
  for (int i = n - 2; i >= 0; i--) { while (m > k && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= 0)m--; ch[m++] = p[i]; }
  if (n > 1)m--;
  ch.resize(m);
  return ch;
}

double diameter2(vector<Point>& points) {
  vector<Point>p = ConvexHull(points);
  int n = p.size();
  if (n == 1) return 0;
  if (n == 2) return Dist2(p[0], p[1]);
  //p.push_back(p[0]); // 免得取模
  double ans = 0;
  for (int u = 0, v = 1; u < n; u++) {
    for (;;) {
      //Cross(p[u+1]-p[u],p[v+1]-p[v])<=0时停止旋转
      int diff = Cross(p[u + 1] - p[u], p[v + 1] - p[v]);
      if (diff <= 0) {
        ans = max(ans, Dist2(p[u], p[v])); // u和v是对踵点
        if (diff == 0) ans = max(ans, Dist2(p[u], p[v + 1])); // diff == 0时u和v+1也是对踵点
        break;
      }
      v = (v + 1) % n;
    }
  }
  return ans;
}

/*---------------------------------------------------------------------------------------------------------------------------*/
struct Line {
  Point P;
  Vector v;
  double ang;
  Line() {}
  Line(Point P, Vector v) :P(P), v(v) { ang = atan2(v.y, v.x); }
  bool operator < (const Line& L)const {
    return ang < L.ang;
  }
};
Point GetLineIntersection(const Line& a, const Line& b) {
  Vector u = a.P - b.P;
  double t = Cross(b.v, u) / Cross(a.v, b.v);
  return a.P + a.v * t;
}
bool OnLeft(Line L, Point p) { return Cross(L.v, p - L.P) > 0; }
vector<Point>HalfplaneIntersection(vector<Line>L) {
  int n = L.size();
  sort(L.begin(), L.end());
  int first, last;
  vector<Point> p(n);
  vector<Line> q(n);
  vector<Point> ans;
  q[first = last = 0] = L[0];
  for (int i = 1; i < n; i++) {
    while (first < last && !OnLeft(L[i], p[last - 1])) last--;
    while (first < last && !OnLeft(L[i], p[first]))first++;
    q[++last] = L[i];
    if (fabs(Cross(q[last].v, q[last - 1].v)) < eps) {
      last--;
      if (OnLeft(q[last], L[i].P))q[last] = L[i];
    }
    if (first < last)p[last - 1] = GetLineIntersection(q[last - 1], q[last]);
  }
  while (first < last && !OnLeft(q[first], p[last - 1]))last--;//删除无用平面
  if (last - first <= 1)return ans;
  p[last] = GetLineIntersection(q[last], q[first]);//计算首尾两个半平面的交点
  //从deque复制到输出中
  for (int i = first; i <= last; i++)ans.push_back(p[i]);
  return ans;
}
bool OnSegment(const Point& p, const Point& a1, const Point& a2) {
  return dcmp(Cross(a1 - p, a2 - p)) == 0 && dcmp(Dot(a1 - p, a2 - p)) < 0;
}
bool SegmentProperIntersection(const Point& a1, const Point& a2, const Point& b1, const Point& b2) {
  double c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1),
    c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);
  return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;
}


int IsPointInPolygon(const Point& p, const vector<Point>& poly) {
  int wn = 0;
  int n = poly.size();
  for (int i = 0; i < n; i++) {
    const Point& p1 = poly[i];
    const Point& p2 = poly[(i + 1) % n];

    if (p1 == p || p2 == p || OnSegment(p, p1, p2)) return -1; // 在边界上
    //if (dcmp(dists(p, p1, p2)) == 0) return 0;

    int k = dcmp(Cross(p2 - p1, p - p1));
    int d1 = dcmp(p1.y - p.y);
    int d2 = dcmp(p2.y - p.y);
    if (k > 0 && d1 <= 0 && d2 > 0) wn++;
    if (k < 0 && d2 <= 0 && d1 > 0) wn--;
  }
  if (wn != 0) return 1; // 内部
  return 0; // 外部
}

bool ConvexPolygonDisjoint(const vector<Point> ch1, const vector<Point> ch2) {
  int c1 = ch1.size();
  int c2 = ch2.size();
  cout << "c1 " << c1 << " " << "c2 " << c2 << endl;
  for (int i = 0; i < c1; i++)
    if (IsPointInPolygon(ch1[i], ch2) != 0) return false; // 内部或边界上
  for (int i = 0; i < c2; i++)
    if (IsPointInPolygon(ch2[i], ch1) != 0) return false; // 内部或边界上
  for (int i = 0; i < c1; i++)
    for (int j = 0; j < c2; j++)
      if (SegmentProperIntersection(ch1[i], ch1[(i + 1) % c1], ch2[j], ch2[(j + 1) % c2])) return false;
  return true;
}
/*---------------------------------------------------------------------------------------------------------------------------*/
struct Circle {
  Point c;
  double r;
  Circle(Point c, double r) :c(c), r(r) {}
  Point point(double a) {
    return Point(c.x + cos(a) * r, c.y + sin(a) * r);
  }
};
double angle(Vector v) { return atan2(v.y, v.x); }
int getCircleCircleIntersection(Circle C1, Circle C2, vector<Point>& sol) {
  double d = Length(C1.c - C2.c);
  if (dcmp(d) == 0) {   //首先圆心要重合
    if (dcmp(C1.r - C2.r) == 0) return -1; //其次半径要相同,然后就可以推出两圆重合
    return 0;
  }
  if (dcmp(C1.r + C2.r - d) < 0) return 0; //相离没交点
  if (dcmp(fabs(C1.r - C2.r) - d) > 0) return 0; //圆在圆中,没有交点
  double a = angle(C2.c - C1.c); //向量C1C2的极角
  double da = acos((C1.r * C1.r + d * d - C2.r * C2.r) / (2 * C1.r * d)); //C1C2到C1P1的角
  Point p1 = C1.point(a - da), p2 = C1.point(a + da);
  sol.push_back(p1);
  if (p1 == p2) return 1; //相切
  sol.push_back(p2);
  return 2; //相交
}
bool isInCircle(Point p, Circle cir) {
  return dcmp(Dist2(p, cir.c) - cir.r * cir.r) < 0;
}
bool check(vector<Point>p, vector<Circle>cir) {
  if (p.empty()) return true;
  for (int i = 0; i < p.size(); i++) {
    bool ok = true;
    Point tp = Point(-p[i].x, -p[i].y);
    for (int j = 1; j < cir.size(); j++)
      if (isInCircle(tp, cir[j])) { ok = false; break; }
    if (ok)return true;
  }
  return false;
}
/*---------------------------------------------------------------------------------------------------------------------------*/

const int N = 200 + 5;
const double pi = acos(-1.0);
typedef long long ll;
//const int mod = 998244353;
struct ship {
  double x, y, step;
  ship(double x, double y, double step) :x(x), y(y), step(step) {}
};
char mp[30][30], temp[30][30];
bool vis[30][30];

int dx[8] = { 0, 0, 1,-1, 1, 1,-1,-1 };
int dy[8] = { 1,-1, 0, 0, 1,-1, 1,-1 };
signed main() {
  int n;
  while (~scanf("%d", &n)) {
    memset(vis, false, sizeof vis);

    vector<Point>tri;
    for (int i = 0; i < 3; i++) {
      double x, y;
      scanf("%lf%lf", &x, &y);
      tri.push_back(Point(x, y));
    }

    for (int i = n - 1; i >= 0; i--)
      scanf("%s", temp[i]);

    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++)
        mp[i][j] = temp[j][i];
    }

    queue<ship>q;
    q.push(ship(0, 0, 0));
    vis[0][0] = true;
    bool o = 0;
    int mn;
    while (q.size() > 0) {
      ship fir = q.front();
      if (fir.x == n - 1 && fir.y == n - 1) { o = 1; mn = fir.step; break; }
      q.pop();
      for (int i = 0; i < 8; i++) {
        int nowx = fir.x + dx[i];
        int nowy = fir.y + dy[i];
        if (nowx >= 0 && nowy >= 0 && nowx < n && nowy < n && !vis[nowx][nowy] && mp[nowx][nowy] != '#') {
          bool ok = 1;
          for (double j = 1; j <= 100; j++) {
            double x = fir.x + dx[i] / 100.0 * j;
            double y = fir.y + dy[i] / 100.0 * j;
            if (IsPointInPolygon(Point(x, y), tri) == 1) {
              ok = 0; break;
            }
          }
          if (ok) {
            vis[nowx][nowy] = true;
            q.push(ship(nowx, nowy, fir.step + 1));
          }
        }
      }

    }
    if (o) printf("%d\n", mn);
    else printf("-1\n");
  }
  return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值