틀을 깨고 생각하라


16

구를 5면 상자에 맞추려고하지만 때로는 완전히 맞지 않는 경우가 있습니다. 상자 바깥에있는 구의 양을 계산하는 함수를 작성하십시오.

가능한 상황은 3 가지입니다.

  • 구가 상자에 완전히 들어갑니다. 답은 0입니다.
  • 구는 상자의 가장자리에 있습니다. 답은 전체 볼륨의 절반 이상입니다.
  • 구는 상자의 바닥에 있습니다.

여기서 각 상황을 볼 수 있습니다.

영상

이 값을 4 자리 이상의 유효 숫자로 계산하려면 프로그램이나 함수를 작성해야합니다.

입력 : 편리한 형식에 상관없이 음이 아닌 실수 4 개 *-너비, 길이, 상자 깊이 (내부 측정) 및 구의 직경.

출력 : 사용 가능한 형식의 음이 아닌 실수 1 개 *-상자 외부에있는 구의 총 부피 (백분율 아님).

* 십진 문자열로 변환 할 수 있어야합니다.

삼각법 사용을 가능한 한 제한하는 것이 좋습니다.

이것은 인기 콘테스트이므로 상자 밖에서 생각하십시오!


예를 들어주세요?
mniip

1
우리는 가정 할 수 상자의 벽이 얇은 무한하다 또는 주어진 치수는 내부 치수입니까? :)
대런 스톤

입력의 최대 값은 얼마입니까?
Blender

@DarrenStone 나는 벽 두께가 중요하지 않다고 생각합니다. 당신은 그것을 무한으로 간주 할 수 있으므로 상자는 무한 블록의 직사각형 구멍이됩니다. 결과는 벽 두께의 다른 값과 동일합니다. 상자 나 구를 물리적으로 깨뜨 리거나, 왜곡하거나, 깎거나 규칙적으로 무언가를함으로써 규칙을 구부리거나 속이려는 경우를 제외하고.
Victor Stafusa

3
@DarrenStone 상자는 멋진 그림을 위해 두께 만 있습니다. 문제는 내부 치수를 처리합니다.
Kendall Frey

답변:


21

앞으로

아래 상자 바깥의 구를 찾으십시오.

"sphere"는 볼륨 계산 기능 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

파이썬 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

파이썬 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 n하고 제거 할 수 있습니다 . from numpy import*n.
Timtech

@Timtech 헤드 업 및 제안에 감사드립니다.
user2487951

1

매스 매 티카

적절한 한계로 수치 적분 사용.

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가되어야합니다.
Sumurai8

@ Sumurai8 "출력 : 상자 밖의 구의 총 부피 ( 백분율 아님)."
Kendall Frey

0

루비

보자 ...
상자가 완전히 안에 있으면 width> diameter; 길이> 직경 및 높이> 직경.
첫 번째 검사가 실행되어야합니다.

바닥에 앉아 있으면 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난 그냥 위로 읽고 있었다" 구형 캡 공식그림은 간단한 그렇게 관계를 제안하지 않습니다. 다시 읽어 볼게요.
Darren Stone

@DarrenStone 이제 되돌아 보면 확실하지 않습니다. 나는 놀랍게도 다운 / 소진되었지만 어느 쪽이든 패치하기가 매우 쉽습니다!

나는 거의 a = wi > le ? le : wi작동 해야 한다고 확신 합니다. 그렇지 않으면 버그가 있습니다.
Konrad Borowski

a = wi>le?le:wi작동하지 않았다. git ruby ​​(2.2 developer)를 실행하고 있기 때문에 불균형이라고 말했을 것입니다.

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)+2rxX와 하나에서 평가 (X 언급 직경 위의 구체 통해 따른 길이의 측정은 R이 구 반경 임) pdbd또는 다른 치수로 발생하는 특정 경우에 따라 구 직경과 상자 깊이의 차이.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.