题目链接:https://vjudge.net/problem/UVALive-2963
题目大意:有n个星球,每个星球坐标为(xi,yi,zi),可以看成一个点。每个星球广播A类节目或B类节目,广播范围为R(以该星球为中心半径为R的球体)。令N+(i)表示星球i听到的和自己广播相同节目的星球数(包括自己),N-(i)表示星球i听到的和自己广播不同节目的星球数。如果N+(i)<N-(i),则称星球i是不稳定的。求不稳定星球的最大数目以及在此前提下R的最小值。
思路:容易知道,R的值肯定为某两个星球之间的距离。因此将所有距离从小到大排序,并存储每个距离所对应的两个点。按顺序枚举每个距离,根据这些距离所对应的点更新N+(i)和N-(i)即可。又因为半径大的球会包含半径小的球,所以前面的结果可以适用于后面。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <map>
#include <iostream>
#include <queue>
using namespace std;
typedef long long LL;
const int dr[] = {0,0,-1,1};
const int dc[] = {-1,1,0,0};
const int maxn = 1000 + 10;
struct Point
{
int x, y, z, t;
}p[maxn];
struct Triple
{
int d, pa, pb;
bool operator < (const Triple& rhs) const {
return d < rhs.d;
}
bool operator == (const Triple &rhs) const {
return d == rhs.d;
}
Triple(int d = 0, int pa = 0, int pb = 0) : d(d),pa(pa),pb(pb){}
}tri[maxn*maxn];
int dist(const Point& A, const Point& B)
{
return (A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y) + (A.z-B.z)*(A.z-B.z);
}
int vis[maxn];
int main()
{
int n;
while(scanf("%d", &n) == 1)
{
for(int i = 0; i < n; i++) scanf("%d%d%d%d", &p[i].x, &p[i].y, &p[i].z, &p[i].t);
int cnt = 0;
for(int i = 0; i < n; i++)
for(int j = i+1; j < n; j++)
tri[cnt++] = Triple(dist(p[i],p[j]), i, j);
sort(tri, tri+cnt);
fill(vis, vis+n+2, 1);
int temp = 0, ans = 0, R = 0, j;
for(int i = 0; i < cnt;) {
for(j = i; j < cnt && tri[j].d == tri[i].d; j++)
{
int ta = tri[j].pa, tb = tri[j].pb;
if(p[ta].t != p[tb].t)
{
if(--vis[ta] == -1) temp++;
if(--vis[tb] == -1) temp++;
}
else {
if(++vis[ta] == 0) temp--;
if(++vis[tb] == 0) temp--;
}
}
if(temp > ans) {
ans = temp;
R = tri[i].d;
}
i = j;
}
printf("%d\n%.4f\n", ans, sqrt(R*1.0));
}
return 0;
}