Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <cstdio>
- #include <complex>
- #include <cstring>
- #include <string>
- #include <cmath>
- #include <cstdlib>
- #include <algorithm>
- #include <vector>
- #include <queue>
- #include <deque>
- #include <set>
- #include <map>
- #include <sstream>
- #include <iostream>
- #include <numeric>
- #include <climits>
- using namespace std;
- int nextInt() {
- int x;
- scanf("%d", &x);
- return x;
- }
- double nextDouble() {
- double x;
- scanf("%lf", &x);
- return x;
- }
- long long nextLong() {
- long long x;
- scanf("%I64d", &x);
- return x;
- }
- const int BUFSIZE = 10000010;
- char buf[BUFSIZE + 1];
- string nextString() {
- scanf("%s", buf);
- return buf;
- }
- string nextLine() {
- gets(buf);
- return buf;
- }
- const bool DEBUG_ON = false;
- template <class T>
- void debug(vector<T> &a, string name) {
- cerr << name << ": ";
- for (int i = 0; i < a.size(); ++i) {
- cerr << a[i] << " ";
- }
- cerr << endl;
- }
- struct Point {
- double x, y;
- Point () {}
- Point (double x, double y) : x(x), y(y) {}
- Point operator + (const Point &op) const { return Point(x + op.x, y + op.y); }
- Point operator - (const Point &op) const { return Point(x - op.x, y - op.y); }
- Point operator * (const double &op) const { return Point(x * op, y * op); }
- double operator * (const Point &op) const { return x * op.x + y * op.y; }
- double operator % (const Point &op) const { return x * op.y - y * op.x; }
- string toString() const {
- stringstream out;
- out << "(" << x << ", " << y << ")";
- return out.str();
- }
- double length() {
- return sqrt(x * x + y * y);
- }
- };
- Point nextPoint() {
- double x = nextDouble();
- double y = nextDouble();
- return Point(x, y);
- }
- struct Moto {
- Point startPoint;
- Point dir;
- int id;
- Moto () {}
- Moto (Point startPoint, Point dir, int id) : startPoint(startPoint), dir(dir), id(id) {}
- };
- Moto nextMoto(int id) {
- Point start = nextPoint();
- Point dir = nextPoint();
- return Moto(start, dir, id);
- }
- const double inf = 1e20;
- const double eps = 1e-9;
- int cmp(double x, double y) {
- double tol = eps * max(1.0, max(fabs(x), fabs(y)));
- return x - y < -tol ? -1 : x - y > tol ? 1 : 0;
- }
- bool isGt(double x, double y) {
- return cmp(x, y) > 0;
- }
- bool isEqual(double x, double y) {
- return cmp(x, y) == 0;
- }
- struct Event {
- int id;
- Point point;
- int kind;
- int winId;
- Event () {}
- Event (int id, Point point, int kind, int winId = -1) : id(id), point(point), kind(kind), winId(winId) {}
- bool operator < (const Event &op) const {
- if (!isEqual(point.x, op.point.x)) {
- return point.x < op.point.x;
- }
- if (kind != op.kind) {
- return kind < op.kind;
- }
- if (!isEqual(point.y, op.point.y)) {
- return point.y < op.point.y;
- }
- if (id != op.id) {
- return id < op.id;
- }
- return winId < op.winId;
- }
- };
- double getIntPar(Point s1, Point e1, Point s2, Point e2) {
- double d = (e1 - s1) % (e2 - s2);
- if (fabs(d) <= eps) {
- return inf;
- }
- return -((s1 - s2) % (e2 - s2)) / d;
- }
- Point getEndPoint(Moto moto, double W, double H) {
- double par = inf;
- vector<pair<Point, Point> > lines;
- for (int m1 = 0; m1 < 4; ++m1) {
- for (int m2 = m1 + 1; m2 < 4; ++m2) {
- int x = m1 ^ m2;
- if ((x & (x - 1)) == 0) {
- Point p1(m1 & 1 ? -W : W, m1 & 2 ? -H : H);
- Point p2(m2 & 1 ? -W : W, m2 & 2 ? -H : H);
- lines.push_back(make_pair(p1, p2));
- }
- }
- }
- Point s = moto.startPoint;
- Point e = moto.startPoint + moto.dir;
- for (int i = 0; i < lines.size(); ++i) {
- double p = getIntPar(s, e, lines[i].first, lines[i].second);
- if (p > eps) {
- par = min(par, p);
- }
- }
- return s + (e - s) * par;
- }
- struct SweepMoto {
- static vector<Moto> *motos;
- static Point sweepPoint;
- int ind;
- SweepMoto (int ind) : ind(ind) {}
- bool operator < (const SweepMoto &op) const {
- double curY = getY();
- double opY = op.getY();
- if (curY != opY) {
- // if (fabs(curY - opY) > eps) {
- return curY < opY;
- }
- return ind < op.ind;
- }
- double getY() const {
- double tol = eps * max(1.0, fabs(sweepPoint.x));
- double x = sweepPoint.x - tol;
- double y = (*motos)[ind].startPoint.y + (*motos)[ind].dir.y * (x - (*motos)[ind].startPoint.x) / (*motos)[ind].dir.x;
- return y;
- }
- };
- vector<Moto> * SweepMoto::motos = 0;
- Point SweepMoto::sweepPoint;
- bool getMotosBreak(Moto &m1, Moto &m2, Point &crossPoint) {
- Point s1 = m1.startPoint;
- Point e1 = s1 + m1.dir;
- Point s2 = m2.startPoint;
- Point e2 = s2 + m2.dir;
- double p1 = getIntPar(s1, e1, s2, e2);
- double p2 = getIntPar(s2, e2, s1, e1);
- if (fabs(p1) <= eps || fabs(p2) <= eps) {
- cerr << "collision found\n" << endl;
- throw 0;
- }
- if (p1 > eps && p2 > eps && p1 < inf) {
- crossPoint = s1 + (e1 - s1) * p1;
- return true;
- }
- return false;
- }
- double getTime(Moto &moto, Point &dst) {
- return (dst - moto.startPoint).length() / moto.dir.length();
- }
- void addMotosBreakEvent(set<Event> &events, Moto &m1, Moto &m2) {
- Point crossPoint;
- if (getMotosBreak(m1, m2, crossPoint)) {
- double t1 = getTime(m1, crossPoint);
- double t2 = getTime(m2, crossPoint);
- if (DEBUG_ON) {
- cerr << "times = " << t1 << " " << t2 << endl;
- }
- int id = t1 > t2 ? m1.id : m2.id;
- events.insert(Event(id, crossPoint, -1, m1.id ^ m2.id ^ id));
- }
- }
- void addMoto(set<SweepMoto> &sweepLine, set<Event> &events, int motoId) {
- set<SweepMoto>::iterator it = sweepLine.insert(SweepMoto(motoId)).first;
- vector<Moto> &motos = *SweepMoto::motos;
- if (it != sweepLine.begin()) {
- set<SweepMoto>::iterator prev = it;
- --prev;
- addMotosBreakEvent(events, motos[prev->ind], motos[it->ind]);
- }
- {
- set<SweepMoto>::iterator next = it;
- if (++next != sweepLine.end()) {
- addMotosBreakEvent(events, motos[next->ind], motos[it->ind]);
- }
- }
- }
- double removeMoto(set<SweepMoto> &sweepLine, set<Event> &events, int motoId, int winId) {
- set<SweepMoto>::iterator it = sweepLine.find(SweepMoto(motoId));
- set<SweepMoto>::iterator winIt = winId == -1 ? sweepLine.end() : sweepLine.find(SweepMoto(winId));
- if (DEBUG_ON) {
- cerr << "winId = " << winId << endl;
- }
- if (it == sweepLine.end() || winId != -1 && winIt == sweepLine.end()) {
- if (DEBUG_ON) {
- cerr << "sweepPoint = " << SweepMoto::sweepPoint.toString() << endl;
- cerr << motoId << " erasing failed" << endl;
- }
- return 0;
- }
- vector<Moto> &motos = *SweepMoto::motos;
- if (it != sweepLine.begin()) {
- set<SweepMoto>::iterator prev = it;
- --prev;
- set<SweepMoto>::iterator next = it;
- if (++next != sweepLine.end()) {
- addMotosBreakEvent(events, motos[prev->ind], motos[next->ind]);
- }
- }
- double res = getTime(motos[it->ind], SweepMoto::sweepPoint) * motos[it->ind].dir.length();
- sweepLine.erase(it);
- return res;
- }
- double solve(double W, double H, vector<Moto> motos) {
- set<Event> events;
- for (int i = 0; i < motos.size(); ++i) {
- events.insert(Event(i, motos[i].startPoint, +1));
- Point endPoint = getEndPoint(motos[i], W, H);
- if (DEBUG_ON) {
- cerr << i << " " << endPoint.toString() << endl;
- }
- events.insert(Event(i, endPoint, -1));
- }
- SweepMoto::motos = &motos;
- set<SweepMoto> sweepLine;
- double res = 0;
- while (events.empty() == false) {
- if (DEBUG_ON) {
- cerr << "events size = " << events.size() << " ---------------------" << endl;
- for (set<Event>::iterator it = events.begin(); it != events.end(); ++it) {
- cerr << it->id << " " << it->point.toString() << " " << it->kind << endl;
- }
- cerr << "sweep size = " << sweepLine.size() << endl;
- for (set<SweepMoto>::iterator it = sweepLine.begin(); it != sweepLine.end(); ++it) {
- cerr << it->ind << endl;
- }
- }
- Event curEvent = *events.begin();
- events.erase(events.begin());
- SweepMoto::sweepPoint = curEvent.point;
- if (curEvent.kind == +1) {
- addMoto(sweepLine, events, curEvent.id);
- } else {
- double len = removeMoto(sweepLine, events, curEvent.id, curEvent.winId);
- if (DEBUG_ON) {
- cerr << curEvent.id << ": " << "len = " << len << endl;
- }
- res += len;
- }
- }
- return res;
- }
- double randomDouble() {
- return ((rand() << 15) + rand()) % 1000000 / 1e6;
- //return rand() / double(1 << 15);
- }
- Point randomPoint(double W, double H) {
- int w = W;
- int h = H;
- double x = rand() % w;
- double y = rand() % h;
- //double x = randomDouble() * 2 * W - W;
- //double y = randomDouble() * 2 * H - H;
- return Point(x, y);
- }
- Moto randomMoto(int id, double W, double H) {
- Point start = Point(randomDouble() * 2 * (W - 1) - (W - 1), randomDouble() * 2 * (H - 1) - (H - 1));
- Point dir = Point(randomDouble() * 10 + 0.00001, randomDouble() * 20 - 10);
- return Moto(start, dir, id);
- }
- struct Segment {
- Point s, e;
- Segment (Point s, Point e) : s(s), e(e) {}
- };
- double getDeathTime(Moto m, vector<Moto> &motos, vector<Segment> &walls) {
- double par = inf;
- Point s = m.startPoint;
- Point e = s + m.dir;
- for (int i = 0; i < motos.size(); ++i) {
- if (motos[i].id != m.id) {
- Point ms = motos[i].startPoint;
- Point me = ms + motos[i].dir;
- double p = getIntPar(s, e, ms, me);
- double mp = getIntPar(ms, me, s, e);
- if (mp > eps && p > eps && p > mp) {
- par = min(par, p);
- }
- }
- }
- for (int i = 0; i < walls.size(); ++i) {
- Point ms = walls[i].s;
- Point me = walls[i].e;
- double p = getIntPar(s, e, ms, me);
- double mp = getIntPar(ms, me, s, e);
- if (eps < mp && mp < 1 - eps && p > eps) {
- par = min(par, p);
- }
- }
- return par;
- }
- double solveSlow(double W, double H, vector<Moto> motos) {
- vector<Segment> walls;
- Point p00(-W, -H);
- Point p01(-W, H);
- Point p10(W, -H);
- Point p11(W, H);
- Point dx(1, 0), dy(0, 1);
- walls.push_back(Segment(p00 - dy, p01 + dy));
- walls.push_back(Segment(p00 - dx, p10 + dx));
- walls.push_back(Segment(p11 + dx, p01 - dx));
- walls.push_back(Segment(p11 + dy, p10 - dy));
- double res = 0;
- while (motos.size() > 0) {
- double minTime = inf;
- double minSpeed = inf;
- for (int i = 0; i < motos.size(); ++i) {
- double curTime = getDeathTime(motos[i], motos, walls);
- double curSpeed = motos[i].dir.length();
- if (DEBUG_ON) {
- // cerr << "m: curTime = " << curTime << endl;
- // cerr << "m: curSpeed = " << curSpeed << endl;
- }
- if (isGt(minTime, curTime) || isEqual(minTime, curTime) && isGt(minSpeed, curSpeed)) {
- minTime = curTime;
- minSpeed = curSpeed;
- }
- }
- for (int i = 0; i < motos.size(); ++i) {
- double curTime = getDeathTime(motos[i], motos, walls);
- double curSpeed = motos[i].dir.length();
- if (DEBUG_ON) {
- // cerr << "w: curTime = " << curTime << endl;
- // cerr << "w: curSpeed = " << curSpeed << endl;
- }
- if (minTime == curTime && minSpeed == curSpeed) {
- Point startPoint = motos[i].startPoint;
- Point endPoint = motos[i].startPoint + motos[i].dir * minTime;
- double len = (endPoint - startPoint).length();
- res += len;
- walls.push_back(Segment(startPoint, endPoint));
- // cerr << motos[i].id << " id deleted" << endl;
- if (DEBUG_ON) {
- cerr << motos[i].id << ": " << "len = " << len << endl;
- cerr << "minTime = " << minTime << endl;
- cerr << "minSpeed = " << minSpeed << endl;
- }
- motos.erase(motos.begin() + i);
- break;
- }
- }
- }
- return res;
- }
- int main() {
- {
- for (int seed = 0; seed < 100000; ++seed) {
- srand(seed);
- if (seed % 100 == 0) {
- cerr << "seed = " << seed << endl;
- }
- //cout << seed << ": " << res << endl;
- int n = 100;//((rand() << 15) + rand()) % 20 + 1;
- double W = 10000;
- double H = 10000;
- vector<Moto> motos(n);
- for (int i = 0; i < n; ++i) {
- while (true) {
- motos[i] = randomMoto(i, W, H);
- bool ok = true;
- /*
- for (int j = 0; j < i; ++j) {
- Point s1 = motos[i].startPoint;
- Point e1 = s1 + motos[i].dir;
- Point s2 = motos[j].startPoint;
- Point e2 = s2 + motos[j].dir;
- if (fabs((s2 - s1) % motos[i].dir) <= eps
- || fabs((s1 - s2) % motos[j].dir) <= eps) {
- ok = false;
- break;
- }
- double p1 = getIntPar(s1, e1, s2, e2);
- double p2 = getIntPar(s1, e1, s2, e2);
- if (eps < p1 && p1 < inf && eps < p2 && p2 < inf && fabs(p1 - p2) <= eps) {
- ok = false;
- break;
- }
- }
- */
- if (ok) {
- break;
- }
- }
- }
- if (DEBUG_ON) {
- cout << n << " " << W << " " << H << endl;
- for (int i = 0; i < motos.size(); ++i) {
- cout << motos[i].startPoint.x << " " << motos[i].startPoint.y << " " << motos[i].dir.x << " " << motos[i].dir.y << endl;
- }
- }
- double res = solve(W, H, motos);
- double resSlow = solveSlow(W, H, motos);
- cout << ".";
- // cerr << "time = " << clock() << endl;
- if (!(res >= 0)) {
- cerr << "res = " << res << endl;
- cerr << "seed = " << seed << endl;
- break;
- }
- if (fabs(res - resSlow) > 1e-6) {
- cerr << "seed = " << seed << endl;
- cerr.precision(10);
- cerr << res << endl;
- cerr << resSlow << endl;
- cerr << n << " " << W << " " << H << endl;
- for (int i = 0; i < n; ++i) {
- cerr << motos[i].startPoint.x << " " << motos[i].startPoint.y << " " << motos[i].dir.x << " " << motos[i].dir.y << endl;
- }
- break;
- }
- }
- cerr << "OK" << endl;
- return 0;
- }
- //{
- // Point s1(-9000, -5200);
- // Point d1(7.613, -4.7);
- // Point s2(-4000, -8000);
- // Point d2(7.8, -6);
- // Point e1 = s1 + d1;
- // Point e2 = s2 + d2;
- // cerr.precision(20);
- // cerr << ((e1 - s1) % (s2 - s1)) << endl;
- // return 0;
- //}
- freopen("j4.in", "rt", stdin);
- freopen("j4.out", "wt", stdout);
- int n = nextInt();
- double W = nextDouble();
- double H = nextDouble();
- vector<Moto> motos(n);
- for (int i = 0; i < n; ++i) {
- motos[i] = nextMoto(i);
- }
- double res = solve(W, H, motos);
- //double resSlow = solveSlow(W, H, motos);
- //cerr << res << endl;
- //cerr << resSlow << endl;
- if (!(res >= 0)) {
- throw 0;
- }
- printf("%.12lf\n", res / 1000);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement