题目链接
- 题意:
给定n组球心,每一组有两个球体,每一组只能选择一个球。现在需要选n个球,求选择的所有球体的R的最大值且互相不重叠
这题有一个需要注意的点:题目要求最后round后答案仍满足,那么直接取后三位就是答案,直接printf后由于会四舍五入导致wrong - 分析:
每组有两种选择,且互斥,就是twosat的题目了,直接二分R加twosat即可。
将i组和j组的两个球分别标号为0和1,那么当两个球ii和jj不满足当前的R值时,说明i组和j组不能选择ii号球和jj号球,那么即 (i = ii ^ 1) OR (j = jj ^ 1),套用模板加边即可
const double EPS = 1e-9;
const int MAXV = 100010;
struct TwoSAT
{
int n;
vector<int> G[MAXV*2];
bool mark[MAXV*2];
int S[MAXV*2], c;
void init(int n)
{
this->n = n;
for (int i = 0; i < n*2; i++) G[i].clear();
memset(mark, 0, sizeof(mark));
}
bool dfs(int x)
{
if (mark[x^1]) return false;
if (mark[x]) return true;
mark[x] = true;
S[c++] = x;
for (int i = 0; i < G[x].size(); i++)
if (!dfs(G[x][i])) return false;
return true;
}
// x = xval or y = yval
void add_clause(int x, int xval, int y, int yval)
{
x = x * 2 + xval;
y = y * 2 + yval;
G[x^1].push_back(y);
G[y^1].push_back(x);
}
bool solve()
{
for(int i = 0; i < n*2; i += 2)
if(!mark[i] && !mark[i+1])
{
c = 0;
if(!dfs(i))
{
while(c > 0) mark[S[--c]] = false;
if(!dfs(i+1)) return false;
}
}
return true;
}
} tst;
int n, m;
struct Point
{
double x, y, z;
inline void read()
{
scanf("%lf%lf%lf", &x, &y, &z);
}
} ipt[MAXN][2];
inline double dis(Point pa, Point pb)
{
return sqrt(sqr(pa.x - pb.x) + sqr(pa.y - pb.y) + sqr(pa.z - pb.z));
}
bool check(double Min)
{
tst.init(n);
REP(i, n) FF(j, i + 1, n)
{
REP(ii, 2) REP(jj, 2)
{
double d = dis(ipt[i][ii], ipt[j][jj]);
if (d < Min)
{
tst.add_clause(i, ii ^ 1, j, jj ^ 1);
}
}
}
return tst.solve();
}
int main()
{
while (~RI(n))
{
REP(i, n) REP(j, 2)
ipt[i][j].read();
double l = 0, r = 1e20, m;
while (l + EPS < r)
{
m = (l + r) / 2;
if (check(m * 2))
l = m;
else
r = m;
}
printf("%.3f\n", (int)(r * 1000) / 1000.0);
}
return 0;
}