几何+ 贪心区域覆盖。
联立球面方程和空间直线方程,最后方程中只剩下一个未知数,这个未知数用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;
}