题目只需要输出最小的power,不需要求解坐标。直接用二分查找,枚举所有坐标点看是否满足。
找到满足(|xi - x| + |yi - y| + |zi - z|) ≤ piY的最小的Y。
Ahyangyi的代码充分利用了该式的对称性
x + y + z ≤ xi + yi + zi + piY
x + y + z ≥ xi + yi + zi - piY
x + y - z ≤ xi + yi - zi + piY
x + y - z ≥ xi + yi - zi - piY
x - y + z ≤ xi - yi + zi + piY
x - y + z ≥ xi - yi + zi - piY
-x + y + z ≤ -xi + yi + zi + piY
-x + y + z ≥ -xi + yi + zi - piY
即
A ≤ x + y + z ≤ B
C ≤ x + y - z ≤ D
E ≤ x - y + z ≤ F
G ≤ -x + y + z ≤ H
则答案是是满足A<B&&C<D&&E<F&&G<H的最小的Y。
#include <stdio.h> int n; int x[1000], y[1000], z[1000], p[1000]; int test (double pow) { double best[2][2][2]; int a, b, c; for (a = 0; a < 2; a ++) for (b = 0; b < 2; b ++) for (c = 0; c < 2; c ++) best[a][b][c] = 1e20; for (int i = 0; i < n; i ++) for (a = 0; a < 2; a ++) for (b = 0; b < 2; b ++) for (c = 0; c < 2; c ++) best[a][b][c] <?= (a?x[i]:-x[i]) + (b?y[i]:-y[i]) + (c?z[i]:-z[i]) + pow*p[i]; for (a = 0; a < 2; a ++) for (b = 0; b < 2; b ++) for (c = 0; c < 2; c ++) if (best[a][b][c] + best[!a][!b][!c] < 0) return 0; return 1; } int main () { int t, i, ct = 0; for (scanf("%d", &t); t > 0; t --) { scanf("%d", &n); for (i = 0; i < n; i ++) scanf("%d%d%d%d", x + i, y + i, z + i, p + i); double l, m, r; l = 0; r = 1e20; for (int ii = 0; ii < 100; ii ++) { m = (l + r) / 2; if (test(m)) r = m; else l = m; } printf("Case #%d: %.6lf/n", ++ ct, (l + r) / 2); } return 0; }
ACRush的代码则比较规矩,通过不断移动cruiser的位置来逼近最佳点,通用性更强。
const int maxn=1000+5; int n; double X[maxn],Y[maxn],Z[maxn],P[maxn]; double solve(double X0,double Y0,double Z0) { double result=0; for (int i=0;i<n;i++) { double d=fabs(X0-X[i])+fabs(Y0-Y[i])+fabs(Z0-Z[i]); checkmax(result,d/P[i]); } return result; } int main() { // freopen("..//input.txt","r",stdin); // freopen("..//C-small-attempt0.in","r",stdin);freopen("..//C-small-attempt0.out","w",stdout); freopen("..//C-large.in","r",stdin);freopen("..//C-large.out","w",stdout); int testcase; scanf("%d",&testcase); for (int caseId=1;caseId<=testcase;caseId++) { printf("Case #%d: ",caseId); scanf("%d",&n); for (int i=0;i<n;i++) scanf("%lf%lf%lf%lf",&X[i],&Y[i],&Z[i],&P[i]); double X0=0,Y0=0,Z0=0; double L=1e6; double R0=solve(X0,Y0,Z0); for (int step=0;step<1000;step++) { double tmp; tmp=solve(X0-L,Y0,Z0);if (tmp<R0) R0=tmp,X0-=L; tmp=solve(X0+L,Y0,Z0);if (tmp<R0) R0=tmp,X0+=L; tmp=solve(X0,Y0-L,Z0);if (tmp<R0) R0=tmp,Y0-=L; tmp=solve(X0,Y0+L,Z0);if (tmp<R0) R0=tmp,Y0+=L; tmp=solve(X0,Y0,Z0-L);if (tmp<R0) R0=tmp,Z0-=L; tmp=solve(X0,Y0,Z0+L);if (tmp<R0) R0=tmp,Z0+=L; if ((step+1)%6==0) L/=1.618; } printf("%0.12lf/n",R0); } }