[题解]ZOJ Monthly, December 2010 » ZOJ3451

ZOJ3451
ZOJ3451.cpp


#include <cmath>
#include <cstdio>
#include <cassert>

const int WIDTH = 68;
const int LENGTH = 105;
const double GW = 7.32;
const double GH = 2.44;
const double GLEFT = (WIDTH - GW) / 2;
const double GRIGHT = (WIDTH + GW) / 2;
const double EPS = 1e-8;
const double GRAVITY = 9.80665;
const double LIMIT = 4.0 / 3.0;

// x > 0
// y > 0
// v > 0
// dz > 0
bool gao(double x, double y, double v, double dx, double dy, double dz) {
	// 方向错误
	if (dy >= 0) {
		return false;
	}

	v /= sqrt(dx * dx + dy * dy + dz * dz);
	dx *= v;
	dy *= v;
	dz *= v;

	double t = -y / dy;
	double xx = x + dx * t;

	// 角度错误
	assert(fabs(xx - GLEFT) > EPS && fabs(xx - GRIGHT) > EPS);
	if (xx <= GLEFT || xx >= GRIGHT) {
		return false;
	}

	// 地滚球
	if (dz == 0) {
		return true;
	}

	// 力量不足
	assert(fabs(t - LIMIT * (2 * dz / GRAVITY)) > EPS);
	if (t > LIMIT * (2 * dz / GRAVITY)) {
		return false;
	}

	double tt, zz;
	while (true) {
		// 最高高度足够低(optional)
		if (0.5 * dz * dz / GRAVITY < GH) {
			return true;
		}
		tt = dz / GRAVITY;

		// 上升阶段
		t = -y / dy;
		if (t <= tt) {
			zz = dz * t - 0.5 * GRAVITY * t * t;
			break;
		}
		y += tt * dy;

		// 下降阶段
		t = -y / dy;
		if (t <= tt) {
			zz = 0.5 * dz * dz / GRAVITY - 0.5 * GRAVITY * t * t;
			break;
		}
		y += tt * dy;

		// 下一次弹起
		dy /= 2;
		dz /= 2;
	}
	assert(fabs(zz - GH) > EPS);
	return zz < GH;
}

int main() {
	int ri = 0, n;
	double x, y, v, dx, dy, dz;

	while (scanf("%lf%lf", &x, &y) != EOF) {
		scanf("%d", &n);
		printf("Case #%d:\n", ++ri);
		for (int i = 0; i < n; ++i) {
			scanf("%lf%lf%lf%lf", &v, &dx, &dy, &dz);
			printf("Shot %d: ", i + 1);
			puts(gao(x, y, v, dx, dy, dz) ? "yes" : "no");
		}
	}

	return 0;
}

//Run ID 	Submit Time 	Judge Status 	Problem ID 	Language 	Run Time(ms) 	Run Memory(KB) 	User Name 	Admin
//604 	2010-12-23 19:14:25 	Accepted 	G 	C++ 	170 	180 	watashi@Zodiac 	Source
One Response to “ZOJ3451”
  1. hflyer says:

    请问滚地球为什么一定是可以的, dy >= 0 为什么一定是不能进的

  2.  
Leave a Reply