【LOJ6407】「ICPC World Finals 2018」跳过罪恶

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/88749767

【题目链接】

【思路要点】

  • 考虑对于每一对点 ( x , y ) (x,y) ,求出 x x 是否能到达 y y ,剩余部分可用 B F S BFS 解决。
  • d = d i s t ( x , y ) , h = h e i g h t y h e i g h t x d=dist(x,y),h=height_y-height_x ,设水平速度为 x x ,竖直速度为 y y ,运动时间为 t t ,则有方程:
    { x t = d y t 1 2 g t 2 = h x 2 + y 2 = v 2 \left\{\begin{aligned}xt & =d \\yt-\frac{1}{2}gt^2 & =h \\x^2+y^2 & = v^2\end{aligned}\right.
  • t t 表示 x , y x,y 代入 ( 3 ) (3) 式,可得
    1 4 g 2 t 4 + ( g h v 2 ) t 2 + ( d 2 + h 2 ) = 0 \frac{1}{4}g^2t^4+(gh-v^2)t^2+(d^2+h^2)=0
  • 由于我们希望 x x 尽可能大从而避免撞在楼上,根据此式,我们需要求解最大的 t t ,从而得到一组使得 x x 尽可能大的 ( x , y ) (x,y)
  • 检验是否撞在楼上只需要考虑处在楼房交界处的时候,可以单独考虑每一条交界处的线段,计算上述抛物线在对应位置的高度与楼房的高度进行比较即可。
  • 时间复杂度 O ( d x 3 d y 3 ) O(d_x^3d_y^3) O ( d x 2 d y 2 ( d x + d y ) ) O(d_x^2d_y^2(d_x+d_y))

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 25;
const int MAXM = 405;
const double eps = 1e-7;
const double g = 9.80665;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct point {double x, y; };
struct line {point a, b; };
point operator + (point a, point b) {return (point) {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) {return (point) {a.x - b.x, a.y - b.y}; }
point operator * (point a, double b) {return (point) {a.x * b, a.y * b}; }
double operator * (point a, point b) {return a.x * b.y - a.y * b.x; }
double moo(point a) {return sqrt(a.x * a.x + a.y * a.y); }
double dis(point a, point b) {return moo(b - a); }
point center[MAXN][MAXN];
double w, v; int n, m, height[MAXN][MAXN], dist[MAXN][MAXN];
pair <double, double> calspeed(int sx, int sy, int tx, int ty) {
	double d = w * sqrt((sx - tx) * (sx - tx) + (sy - ty) * (sy - ty));
	double h = height[tx][ty] - height[sx][sy];
	double a = g * g / 4, b = g * h - v * v, c = d * d + h * h;
	if (b * b - 4 * a * c < eps) return make_pair(-1, -1);
	double t = sqrt((-b + sqrt(b * b - 4 * a * c)) / (2 * a));
	return make_pair(d / t, g * t / 2 + h / t);
}
bool check(line x, line y) {
	if (((y.a - x.a) * (x.b - x.a)) * ((y.b - x.a) * (x.b - x.a)) > eps) return false;
	if (((x.a - y.a) * (y.b - y.a)) * ((x.b - y.a) * (y.b - y.a)) > eps) return false;
	return true;
}
point inter(line x, line y) {
	double tmp = (y.a - x.a) * (y.b - x.a);
	double tnp = (y.b - x.b) * (y.a - x.b);
	return (x.a * tnp + x.b * tmp) * (1 / (tmp + tnp));
}
bool reach(int sx, int sy, int tx, int ty) {
	pair <double, double> speed = calspeed(sx, sy, tx, ty);
	double x = speed.first, y = speed.second;
	if (x == -1 && y == -1) return false;
	line main = (line) {center[sx][sy], center[tx][ty]};
	for (int i = min(sx, tx); i <= max(sx, tx); i++)
	for (int j = min(sy, ty); j <= max(sy, ty); j++) {
		point ru = (point) {(i - 1) * w, j * w};
		point rd = (point) {i * w, j * w};
		point ld = (point) {i * w, (j - 1) * w};
		line r = (line) {ru, rd}, d = (line) {ld, rd};
		if (check(r, main)) {
			double t = dis(inter(r, main), center[sx][sy]) / x;
			double h = y * t - g * t * t / 2 + height[sx][sy];
			if (h < max(height[i][j], height[i][j + 1]) - eps) return false;
		}
		if (check(d, main)) {
			double t = dis(inter(d, main), center[sx][sy]) / x;
			double h = y * t - g * t * t / 2 + height[sx][sy];
			if (h < max(height[i][j], height[i + 1][j]) - eps) return false;
		}
	}
	return true;
}
int main() {
	read(m), read(n), read(w), read(v);
	int sx, sy; read(sy), read(sx);
	for (int i = 1; i <= n; i++)
	for (int j = 1; j <= m; j++) {
		read(height[i][j]);
		center[i][j] = (point) {(i - 0.5) * w, (j - 0.5) * w};
	}
	memset(dist, -1, sizeof(dist));
	deque <pair <int, int>> q;
	q.emplace_back(sx, sy), dist[sx][sy] = 0;
	while (!q.empty()) {
		int x = q.front().first;
		int y = q.front().second;
		for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++) {
			if (dist[i][j] != -1) continue;
			if (reach(x, y, i, j)) {
				dist[i][j] = dist[x][y] + 1;
				q.emplace_back(i, j);
			}
		}
		q.pop_front();
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++)
			if (dist[i][j] == -1) printf("X ");
			else printf("%d ", dist[i][j]);
		printf("\n");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/88749767