首页 > 其他 > 详细

BZOJ 1094. [ZJOI2007]粒子运动

时间:2020-01-27 16:25:24      阅读:70      评论:0      收藏:0      [点我收藏+]



首先,不知道为什么用了 long double 之后在wsl和cmd跑出来的结果不一样。。看了老半天老是发现不了错。

把圆心平移到坐标原点方便后面计算。

预处理出每个粒子的轨迹,当前位置为 $p$,速度为 $v$,设碰撞点为 $q$,$q=p+tv$,可以得到方程 $(p_x + t v_x)^2 + (p_y + tv_y)^2 = r ^ 2$,$(v_x^2 + v_y^2)t^2 + 2(p_xv_x + p_yv_y)t+(p_x^2+p_y^2-r^2)=0$,就可以得到 $q$ 的坐标和所需的时间,通过 $p$ 到 $q$ 所需的时间等于 $q$ 到 ($p$ 关于 $Oq$ 的对称点)的时间相等,求个对称点就能得到反射之后的速度。

然后暴力枚举两个点,计算 $2k$ 段距离,列出方程就是二次函数求极值。

技术分享图片
#include <bits/stdc++.h>

#define db long double
const db eps = 1e-8;
const db pi = acos(-1.0);
const int N = 110;

inline int sign(db k) { return k < -eps ? -1 : k > eps; }
inline int cmp(db k1, db k2) { return sign(k1 - k2); }

struct P {
  db x, y;
  P() {}
  P(db x, db y): x(x), y(y) {}
  P operator + (const P &p) const { return {x + p.x, y + p.y}; }
  P operator - (const P &p) const { return {x - p.x, y - p.y}; }
  P operator * (db k) const { return {x * k, y * k}; }
  P operator / (db k) const { return {x / k, y / k}; }
  bool operator < (const P &p) const {
    int c = cmp(x, p.x);
    return c ? c == -1 : cmp(y, p.y) == -1;
  }
  bool operator == (const P &p) const {
    return !cmp(x, p.x) && !cmp(y, p.y);
  }
  db distTo(const P &p) const { return (*this - p).abs(); }
  db alpha() { return atan2(y, x); }
  void read() { double a, b; scanf("%lf%lf", &a, &b); x = a, y = b; }
  //void print() { printf("%.10f %.10f\n", x, y); }
  db abs() { return sqrt(abs2()); }
  db abs2() { return x * x + y * y; }
  P rot(const db &k) { return P(x * cos(k) - y * sin(k), x * sin(k) + y * cos(k)); }
  P rot90() { return P(-y, x); }
  P unit() { return *this / abs(); }
  P normal() { return rot90() / abs(); }
  int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
  P getdel() {if (sign(x) == -1 || (sign(x) == 0 && sign(y) == -1)) return (*this) * (-1); else return (*this);}
  db dot(const P &p) { return x * p.x + y * p.y; }
  db det(const P &p) { return x * p.y - y * p.x; }
} o;

struct L {
  P p, v;
  void read() { 
    p.read(); v.read(); 
  }
} A[N][N];
int n, k;
db r, cost[N][N];

// 投影
P proj(const P &p1, const P &p2, const P &q) {
  P dir = p2 - p1;
  return p1 + dir * (dir.dot(q - p1) / dir.abs2());
}

// 反射
P reflect(const P &p1, const P &p2, const P &q) {
  return proj(p1, p2, q) * 2 - q;
}

db solve(int x, int y, int k1, int k2, db t1, db t2) {
  P p = (A[x][k1].p - A[x][k1].v * cost[x][k1]) - (A[y][k2].p - A[y][k2].v * cost[y][k2]), q = A[x][k1].v - A[y][k2].v;
  db a = q.abs2(), b = 2 * p.dot(q), c = p.abs2();
  if (!a) return std::min(sqrt(t1 * b + c), sqrt(t2 * b + c));
  db t = -b / (2.0 * a);
  if (t > t1 && t < t2) return sqrt(a * t * t + b * t + c);
  return std::min(a * t1 * t1 + b * t1 + c, a * t2 * t2 + b * t2 + c);
}

int main() {
  o.read();
  double rr;
  scanf("%lf", &rr);
  r = (db)rr;
  scanf("%d%d", &n, &k);
  for (int i = 1; i <= n; i++) {
    A[i][0].read();
    A[i][0].p = A[i][0].p - o;
  }
  o.x = o.y = 0;
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= k; j++) {
      P p = A[i][j - 1].p, q = A[i][j - 1].v;
      db a = q.abs2(), b = 2 * p.dot(q), c = p.abs2() - r * r;
      db t = (-b + sqrt(b * b - 4 * a * c)) / (a * 2);
      cost[i][j] = cost[i][j - 1] + t;
      A[i][j].p = A[i][j - 1].p + A[i][j - 1].v * t;
      P re = reflect(o, A[i][j].p, A[i][j - 1].p);
      A[i][j].v = (re - A[i][j].p) / t;
    }
  }
  db ans = 1e10;
  for (int i = 1; i <= n; i++) 
    for (int j = i + 1; j <= n; j++) {
      int k1 = 0, k2 = 0;
      while (k1 < k && k2 < k) {
        ans = std::min(ans, solve(i, j, k1, k2, std::max(cost[i][k1], cost[j][k2]), std::min(cost[i][k1 + 1], cost[j][k2 + 1])));
        if (cost[i][k1 + 1] < cost[j][k2 + 1]) k1++;
        else k2++;
      }
    }
  printf("%.3Lf\n", ans);
  return 0;
}
View Code

 

BZOJ 1094. [ZJOI2007]粒子运动

原文:https://www.cnblogs.com/Mrzdtz220/p/12236227.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!