题目链接:FZU 2144 Shooting Game
几何+ 贪心区域覆盖。
联立球面方程和空间直线方程,最后方程中只剩下一个未知数,这个未知数用s = vt + d表示,这就有了一个以时间为未知数的一元二次方程,再用求根公式判断两个根是否符合实际。
按照进入球形区域的时间排序,之后就是贪心区域覆盖的问题了。
卡时间,直接按照doube输入超时,得用int再转化。
#include <iostream> #include <stdio.h> #include <cmath> #include <algorithm> using namespace std; const int MAX_N = 10000 + 1000; struct Mosquito { double in_time, out_time; Mosquito(){in_time = out_time = 0;} bool operator < (const Mosquito &b) const { return in_time < b.in_time; } }; int T, n, r, cnt, _count, num; Mosquito mosquitos[MAX_N]; int main() { scanf("%d", &T); num = 0; while(T--) { cnt = 0; _count = 1; scanf("%d%d", &n, &r); int x, y, z, dx, dy, dz; double a , b, c, flag, t1, t2, time; for(int i = 0; i < n; i++) { scanf("%d%d%d", &x, &y, &z); scanf("%d%d%d", &dx, &dy, &dz); a = ((dx * 1.0) * (dx * 1.0) + (dy * 1.0) * (dy * 1.0) + (dz * 1.0) * (dz *1.0)); b = 2 * ((dx * 1.0) * (x * 1.0) + (dy *1.0) * (y * 1.0) + (dz * 1.0) * (z * 1.0)); c = ((x * 1.0) * (x * 1.0) + (y * 1.0) * (y * 1.0) +(z * 1.0) * (z * 1.0) - (r * 1.0) * (r * 1.0)); flag = (b * b) - 4 * a *c; if(flag >=0) { t1 = (-b + sqrt(flag)) / (2 * a); t2 = (-b - sqrt(flag)) / (2 * a); if(t1 < 0 && t2 < 0) continue; if(t1 > t2) swap(t1, t2); if(t1 >= 0 && t2 >= 0)//蚊子踪迹与球面相切(t1 == t2 == 0),或者蚊子开始在球的外边(0 < t1 < t2 )或在表面而且正在向内走。 { mosquitos[cnt].in_time = t1; mosquitos[cnt].out_time = t2; cnt++; } else if(t1 < 0 && t2 >= 0)//蚊子开始在球的里边或在表面而且正在向外走 { mosquitos[cnt].in_time = 0; mosquitos[cnt].out_time = t2; cnt++; } } } if(cnt == 0) { printf("Case %d: %d %d\n", ++num, cnt, 0); continue; } sort(mosquitos, mosquitos + cnt); time = mosquitos[0].out_time; for(int i = 1; i < cnt; i++) { if(mosquitos[i].in_time > time) { _count++; time = mosquitos[i].out_time; } time = min(time, mosquitos[i].out_time); } printf("Case %d: %d %d\n", ++num, cnt, _count); } return 0; }