外箱思考


16

您试图将球体装入5边形的盒子中,但有时不能完全适合。编写一个函数来计算球体在框的外部(框的边缘上方)有多少。

有3种可能的情况:

  • 球体完全适合盒子。答案将为0。
  • 球体位于盒子的边缘。答案将超过总数的一半。
  • 球体位于盒子的底部。

您可以在此处查看每种情况:

图片

您必须编写一个程序或函数来将此值计算为至少4个有效数字。

输入:4个非负实数,采用任何方便的格式*-宽度,长度,盒子的深度(内部度量)和球体的直径。

输出:1个可用格式的非负实数*-框外球体的总体积(不是百分比)。

*必须与十进制字符串可相互转换

鼓励您尽可能限制使用三角函数。

这是一场人气比赛,所以跳出框框思考吧!


有什么例子吗?
mniip 2014年

1
我们可以假设无论在箱壁是无限薄给出的尺寸是内部尺寸?:)
Darren Stone

输入的最大值是多少?
Blender 2014年

@DarrenStone我认为墙壁的厚度并不重要。您也可以认为它是无限的,因此该框将是无限块中的矩形孔。结果将与壁厚的任何其他值相同。除非您打算通过物理破坏,扭曲或切开盒子或球体来弯曲/欺骗规则,或者要做一些非常奇怪的事情。
Victor Stafusa 2014年

3
@DarrenStone盒子的厚度仅用于制作精美照片。问题涉及内部尺寸。
Kendall Frey 2014年

Answers:


21

向前

请在下面的盒子外面找到一个球体。

“球体”是体积计算功能f。参考测试用例组成了“盒子”。

                     ( x y z d -- v )
                 : f { F: z F: d } d f2/ 
              { F: r } fmin { F: m } m f2/ {
             F: b } d m f<= d z f<= and if 0e
             else r r r f* b b f* f- fsqrt f-
              { F: t } d m f<= t z f> or if d 
               z f- else d t f- then r 3e f* 
                  fover f- pi f* fover f*
                      f* 3e f/ then ;

                     1e                 1e      
                     1e                 1e 
                     f                  f. 
            cr       1e        1e       0e      
            1e       f         f.       cr 
            1e       1e 0.5e 1e f f. cr 1e 
            0.999e 1e          1e     f  
            f.  cr            0.1e 1e   
            1.000e 0.500e f f. cr

输出:

0. 
0.523598775598299 
0.261799387799149 
0.279345334323962 
0.0654299441440212 

5

Java-基于整数

该程序不使用pi,并且不调用任何外部函数-甚至sqrt。它仅使用简单的算术题- ,,+ 和。此外,除了缩放步骤外,它还专门处理整数。它基本上将球体分成小立方体,并计算盒子外的立方体。-*/

public class Box {
    private static final int MIN = 10000;
    private static final int MAX = MIN * 2;

    private static final int[] SQ = new int[MAX * MAX + 1];

    static {
        int t = 1;
        for (int i = 1; i <= MAX; ++i) {
            while (t < i * i) SQ[t++] = i - 1;
        }
        SQ[MAX * MAX] = MAX;
    }

    public static long outsideInt(int r, int w, int z) {
        int r2 = r * r;
        int o = z - r + 1;
        if (w < r * 2) {
            int t = 1 - SQ[r2 - w * w / 4];
            if (t < o) o = t;
        }
        long v = 0;
        for (int i = o; i <= r; ++i) {
            int d = r2 - i * i;
            int j0 = SQ[d];
            v += 1 + 3 * j0;
            for (int j = 1; j <= j0; ++j)
                v += 4 * SQ[d - j * j];
        }
        return v;
    }

    public static double outside(double x, double y, double z, double d) {
        double f = 1;
        double w = x < y ? x : y;
        double r = d / 2;
        while (r < MIN) {
            f *= 8;
            r *= 2;
            w *= 2;
            z *= 2;
        }
        while (r > MAX) {
            f /= 8;
            r /= 2;
            w /= 2;
            z /= 2;
        }
        return outsideInt((int) r, (int) w, (int) z) / f;
    }

    public static void main(final String... args) {
        System.out.println(outside(1, 1, 1, 1));
        System.out.println(outside(1, 1, 0, 1));
        System.out.println(outside(1, 1, 0.5, 1));
        System.out.println(outside(1, 0.999, 1, 1));
        System.out.println(outside(0.1, 1, 1, 0.5));
    }
}

输出:

0.0
0.5235867850933005
0.26178140856157484
0.27938608275528054
0.06542839088004015

以这种形式,该程序需要超过2GB的内存(可在-Xmx2300m此处使用),而且速度很慢。它使用内存来预先计算一堆平方根(算术);这不是真正必要,但如果没有这样做,它将慢很多。为了同时提高内存需求和速度,请减小MIN常量的值(尽管那样会降低精度)。


2

Python 2(基于数组的方法)

如果该网格中的特定正方形位于圆内或圆外,则它将创建具有真值的数组数组。绘制的圆越大,它应该越精确。然后,它选择某一行下方或上方的区域,计算属于该圆的正方形的数量,然后将其除以整个圆中的正方形的数量。

import math as magic
magic.more = magic.pow
magic.less = magic.sqrt

def a( width, length, depth, diameter ):
  precision = 350 #Crank this up to higher values, such as 20000

  circle = []
  for x in xrange(-precision,precision):
    row = []
    for y in xrange(-precision,precision):
      if magic.less(magic.more(x, 2.0)+magic.more(y, 2.0)) <= precision:
        row.append(True)
      else:
        row.append(False)
    circle.append(row)

  if min(width,length,depth) >= diameter:
    return 0
  elif min(width,length) >= diameter:
    row = precision*2-int(precision*2*float(depth)/float(diameter))
    total = len([x for y in circle for x in y if x])
    ammo = len([x for y in circle[:row] for x in y if x])
    return float(ammo)/float(total)
  else:
    #Why try to fit a sphere in a box if you can try to fit a box on a sphere
    maxwidth = int(float(precision*2)*float(min(width,length))/float(diameter))
    for row in xrange(0,precision*2):
      rowwidth = len([x for x in circle[row] if x])
      if rowwidth > maxwidth:
        total = len([x for y in circle for x in y if x])
        ammo = len([x for y in circle[row:] for x in y if x])
        return float(ammo)/float(total)

2

Python 2.7,球冠公式

在某些情况下,此版本将引发运行时警告,但仍会输出正确的答案。

import numpy as n
x,y,z,d=(float(i) for i in raw_input().split(' '))
r=d/2
V=4*n.pi*r**3/3
a=n.sqrt((d-z)*z)
b=min(x,y)/2
h=r-n.sqrt(r**2-b**2)
c=lambda A,H: (3*A**2+H**2)*n.pi*H/6
print(0 if d<=z and r<=b else c(a,d-z) if r<=b and z>r else V-c(a,z) if r<=b or z<h else V-c(b,h))

如果再输入11个字符,我可以摆脱警告。

import math as m
x,y,z,d=(float(i) for i in raw_input().split(' '))
r=d/2
V=4*m.pi*r**3/3
if d>z:
    a=m.sqrt((d-z)*z)
b=min(x,y)/2
h=r-m.sqrt(r**2-b**2)
c=lambda A,H: (3*A**2+H**2)*m.pi*H/6
print(0 if d<=z and r<=b else c(a,d-z) if r<=b and z>r else V-c(a,z) if r<=b or z<h else V-c(b,h))

以下是在版本1上运行的测试用例:

$ python spherevolume.py
1 1 1 1
0
$ python spherevolume.py
1 1 0 1
0.523598775598
$ python spherevolume.py
1 1 .5 1
0.261799387799
$ python spherevolume.py
1 .999 1 1        
0.279345334324
$ python spherevolume.py
.1 1 1 0.5
spherevolume.py:65: RuntimeWarning: invalid value encountered in sqrt
  a=n.sqrt((d-z)*z) or b
0.065429944144

尽管这不是代码高尔夫球,可以缩短import numpy as nfrom numpy import*和带走所有的n.在你的代码。
Timtech

@Timtech感谢您的注意和建议。
user2487951 2014年

1

Mathematica

使用具有适当限制的数值积分。

f[width_, length_, height_, diam_] := 
 With[{r = diam/2, size = Min[width, length]/2},
  Re@NIntegrate[
    Boole[x^2 + y^2 + z^2 < r^2], {x, -r, r}, {y, -r, r}, 
      {z, -r, Max[-r, If[size >= r, r - height, Sqrt[r^2 - size^2]]]}]
  ]

0

参考实现-C#

using System;

namespace thinkoutsidethebox
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(OutsideTheBox(1, 1, 1, 1));
            Console.WriteLine(OutsideTheBox(1, 1, 0, 1));
            Console.WriteLine(OutsideTheBox(1, 1, 0.5, 1));
            Console.WriteLine(OutsideTheBox(1, 0.999, 1, 1));
            Console.WriteLine(OutsideTheBox(0.1, 1, 1, 0.5));
        }

        static double OutsideTheBox(double x, double y, double z, double d)
        {
            x = Math.Min(x, y);
            double r = d / 2; // radius
            double xr = x / 2; // box 'radius'
            double inside = 0; // distance the sphere sits inside the box
            if (d <= x && d <= z) // it fits
            {
                return 0;
            }
            else if (d <= x || r - Math.Sqrt(r * r - xr * xr) > z) // it sits on the bottom
            {
                inside = z;
            }
            else // it sits on the rim
            {
                inside = r - Math.Sqrt(r * r - xr * xr);
            }
            // now use the formula from Wikipedia
            double h = d - inside;
            return (Math.PI * h * h / 3) * (3 * r - h);
        }
    }
}

输出:

0
0.523598775598299
0.261799387799149
0.279345334323962
0.0654299441440212

我不明白这些结果。第一个显然是0。第二个没有高度,所以一个应该为1。第三个可以容纳球,并且球的一半正好在上面(答案应为0.5)。案例4中的盒子有点小,所以放在盒子的顶部。答案应略大于0.5。最后一个答案应大于0.5,因为宽度/长度不足以将球放入内部。
Sumurai14年

@ Sumurai8“输出:盒子外面的球体的总体积(不是百分比)。”
肯德尔·弗雷

0

红宝石

让我们看看...
如果盒子完全在里面,则宽度>直径;长度>直径和高度>直径。
那应该是运行的第一个检查。

如果它位于底部,则w> d; l> d和h V=(pi*h^2 /3)*(3r-h)因此,在这种情况下,我们只是获得高度并通过该高度。

如果卡住了,我们可以使用类似的公式(V=(pi*h/6)*(3a^2 + h^2))。实际上,我们之前的公式就是基于这个公式!本质上,我们使用它,而a只是w和l中的较小者。(提示,我们可以通过这样做来获得身高h=r-a

现在的代码!

def TOTB(wi,le,hi,di)
  if wi>=di and le>=di and hi>=di
    res = 0
  elsif wi>=di and le>=di
    r = di/2
    res = 3*r
    res -= hi
    res *= Math::PI
    res *= hi*hi
    res /= 3
  else
    r = di/2
    if wi>le
      a=le
    else
      a=wi
    end #had issues with the Ternary operator on ruby 2.2dev
    h = r-a
    res = 3*a*a
    res += h*h
    res *= Math::PI
    res *= h
    res /= 6
  end
  res
end

注意**我没有对它进行过多的测试,因此可能会出现错误,如果有人注意到了,请告诉我!
数学是可靠的。
较短的版本:

v1 = ->r,h{(3*r -h)*Math::PI*h*h/3}
v2 = ->r,a{h=r-a;((3*a*a)+(h*h))*h*Math::PI/6}
TOTB = ->wi,le,hi,di{(di<wi&&di<le&&di<hi)?0:((di<wi&&di<le)?v1[di/2,hi]:v2[di/2,((wi>le)?le:wi)])}

(现在,我可以肯定的是,为v2获取h的方法有所不同,但稍后会进行修复。


真好 该代码读起来很清楚。但是您确定以下声明吗?“我们可以通过这样做来获得高度h=r-a”,我只是在阅读球冠公式,而该并没有暗示这样简单的关系。我再读一遍。
达伦·斯通

@DarrenStone现在,我不确定。我非常沮丧/疲惫,但是无论哪种方式,都很容易打补丁!

我几乎确定a = wi > le ? le : wi应该可以。否则,您将遇到错误。
Konrad Borowski14年

a = wi>le?le:wi不工作。我猜是因为我正在运行git ruby​​(2.2开发人员),所以可能说不平衡。

0

C ++

#define _USE_MATH_DEFINES   //so I can use M_PI
#include <math.h>           //so I can use sqrt()
#include <iostream>
#include <algorithm>

using namespace std;


int main()
{
    double w;
    double l;
    double d;
    double sd;
    double min_wl;
    double pdbd;
    double sl;
    cin >> w >> l >> d >> sd;

    min_wl = min(w, l);
    if(sd <= min_wl)
    {
        pdbd = 0.0;
    } else
    {
        pdbd = (sqrt((((sd/2)*(sd/2))-((min_wl/2)*(min_wl/2)))) + (sd/2));
    }
    sl = sd - d;

    if(sd <= min(min_wl, d))
    {
        cout << 0;
        return 0;
    } else if((sl < pdbd) && (pdbd > 0.0))    //sits on lip of box
    {
        cout << (M_PI * (((sd/2) * pdbd * pdbd) - ((pdbd * pdbd * pdbd)/(3))));
        return 0;
    } else                  //sits on bottom of box
    {
        cout << (M_PI * (((sd/2) * sl * sl)-((sl * sl * sl)/(3))));
        return 0;
    }
    return 0;
}

我的代码找到了半圆的某些部分的图形的旋转实体的体积。 pdbd保持球体表面上接触盒子的嘴唇的点的投影到球体直径的线性距离,如果延伸,该直径将垂直于盒子的底部。包含两个表达式M_PI基本上是抗衍生物的积分pi * -(x^2)+2rx相对于x(其中,x是沿所提到的直径以上通过球体和长度的度量,其中r是球体的半径)在任一评价pdbd或球形直径和盒子深度的差异取决于在不同尺寸下发生的特殊情况。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.