宝探し (KUPC 2012)

http://kupc2012.contest.atcoder.jp/tasks/kupc2012_9#

問題

解法

解説参照。デバック時間は測定忘れた。

// Implement 30min
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <set>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const long double EPS = 1e-9;
static const long double PI = acos(-1.0);

#define REP(i, n) for (ll i = 0; i < (ll)(n); i++)
#define FOR(i, s, n) for (ll i = (s); i < (ll)(n); i++)
#define FOREQ(i, s, n) for (ll i = (s); i <= (ll)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

#include <complex>

typedef complex<long double> Point;
typedef vector<Point> Polygon;
long double INF = 2e+4;

#define CURR(P, i) (P[i])
#define NEXT(P, i) (P[(i + 1) % P.size()])

struct Line : public vector<Point> {
  Line() {;}
  Line(Point a, Point b) { push_back(a); push_back(b); }
};

struct Circle {
  Point p;
  long double r;
  Circle() {;}
  Circle(Point p, long double r) : p(p), r(r) {;}
};

namespace std {
  bool operator<(const Point &lhs, const Point &rhs) {
    return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
  }
}

inline long double cross(const Point &a, const Point &b) {
  return imag(conj(a) * b);
}

inline long double dot(const Point &a, const Point &b) {
  return real(conj(a) * b);
}

inline int ccw(Point a, Point b, Point c) {
  b -= a;
  c -= a;
  if (cross(b, c) > 0) { return 1; }
  if (cross(b, c) < 0) { return -1; }
  if (dot(b, c) < 0) { return 2; }
  if (norm(b) < norm(c)) { return -2; }
  return 0;
}

bool intersectSP(const Line &s, const Point &p) {
  return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS;
}

Point crosspointSS(const Line &l, const Line &m) {
  long double A = cross(l[1] - l[0], m[1] - m[0]);
  long double B = cross(l[1] - l[0], l[1] - m[0]);
  if (abs(A) < EPS && abs(B) < EPS) {
    if (intersectSP(l, m[0])) { return m[0]; }
    if (intersectSP(l, m[1])) { return m[1]; }
    if (intersectSP(m, l[0])) { return l[0]; }
    if (intersectSP(m, l[1])) { return l[1]; }
    return m[0];
  }
  if (abs(A) < EPS) { assert(false); }
  return m[0] + B / A * (m[1] - m[0]);
}

Polygon ConvexCut(const Polygon &P, const Line &l) {
  Polygon Q;
  for (int i = 0; i < (int)P.size(); i++) {
    Point A = CURR(P, i), B = NEXT(P, i);
    if (ccw(l[0], l[1], A) != -1) { Q.push_back(A); }
    if (ccw(l[0], l[1], A) * ccw(l[0], l[1], B) < 0) {
      Q.push_back(crosspointSS(Line(A, B), l));
    }
  }
  return Q;
}

//============================================================

Point Gravity(const Polygon &poly) {
  Point p(0.0, 0.0);
  long double w = 0.0;
  REP(i, poly.size()) {
    Point q1 = CURR(poly, i);
    Point q2 = NEXT(poly, i);
    long double v = cross(q1, q2);
    Point p2 = (q1 + q2) / 3.0L;
    p = (p * w + p2 * v) / (v + w);
    w += v;
    if (fabs(w) < EPS) { p = q2; }
  }
  return p;
}

Line DegToLine(Point center, long double deg) {
  long double rad = deg * PI / 180.0;
  Point vect(cos(rad), sin(rad));
  return Line(center - vect * INF, center + vect * INF);
}

//============================================================
const int QUERY_MAX = 200;
int query = 0;
void End(Point p) {
  printf("! %.8Lf %.8Lf\n", p.real(), p.imag());
  //fprintf(stderr, "%.8f %.8f\n", p.real(), p.imag());
  fflush(stdout);
}
long double Query(Point p) {
  if (query == QUERY_MAX) { return -1000.0; }
  printf("? %.8Lf %.8Lf\n", p.real(), p.imag());
  fflush(stdout);
  query++;
  long double ret;
  int v = scanf("%Lf", &ret);
  assert(v == 1);
  return ret;
}

long double w, h, E;
Polygon poly;
int main() {
  int v = scanf("%Lf %Lf %Lf", &w, &h, &E);
  assert(v == 3);
  poly.push_back(Point(-w, -h));
  poly.push_back(Point(w, -h));
  poly.push_back(Point(w, h));
  poly.push_back(Point(-w, h));
  REP(iter, 40) {
    Polygon ppoly = poly;
    Point g = Gravity(poly);
    vector<long double> degs;
    while (true) {
      long double theta = Query(g);
      if (theta == -1000.0) { goto end; }
      if (E < 90) {
        Line l = DegToLine(g, theta - 90.0);
        poly = ConvexCut(poly, l);
        goto next;
      } else {
        degs.push_back(theta);
        degs.push_back(theta + 360);
        degs.push_back(theta - 360);
        sort(degs.begin(), degs.end());
        REP(j, degs.size()) {
          REP(i, j) {
            long double diff = degs[j] - degs[i];
            if (60 <= diff && diff <= 120) {
              //fprintf(stderr, "Poly:%d\n", poly.size());
              //FORIT(it, poly) {
              //  fprintf(stderr, "(%f %f) ", it->real(), it->imag());
              //}
              //fprintf(stderr, "G:%f %f\n", g.real(), g.imag());
              //fprintf(stderr, "%f %f\n", degs[i] + 360, degs[j] + 360);
              Line l1 = DegToLine(g, degs[i] + E - 180);
              Line l2 = DegToLine(g, degs[j] - E);
              poly = ConvexCut(poly, l1);
              poly = ConvexCut(poly, l2);
              goto next;
            }
          }
        }
      }
    }
next:;
    if (poly.size() == 0) { poly = ppoly; }
  }
end:
  End(Gravity(poly));
}