pensando fora da caixa


16

Você está tentando encaixar uma esfera em uma caixa de 5 lados, mas às vezes ela não se encaixa completamente. Escreva uma função para calcular quanto da esfera está fora (acima da borda) da caixa.

Existem 3 situações possíveis:

  • A esfera se encaixa completamente na caixa. A resposta será 0.
  • A esfera fica na borda da caixa. A resposta será mais da metade do volume total.
  • A esfera fica no fundo da caixa.

Você pode ver cada situação aqui:

Imagem

Você deve escrever um programa ou função para calcular esse valor em pelo menos 4 dígitos significativos.

Entrada: 4 números reais não negativos, em qualquer formato que seja conveniente * - largura, comprimento, profundidade da caixa (medidas internas) e diâmetro da esfera.

Saída: 1 número real não negativo em um formato utilizável * - o volume total (não a porcentagem) da esfera fora da caixa.

* deve ser conversível em / de uma sequência decimal

Você é encorajado a limitar o uso de trigonometria o máximo possível.

Este é um concurso de popularidade, então pense fora da caixa!


algum exemplo de casos por favor?
Mniip

11
Podemos assumir que as paredes da caixa são infinitamente finas ou as dimensões dadas são dimensões interiores? :)
Darren Pedra

Quais são os valores máximos para as entradas?
Blender

@ DarrenStone Acho que a espessura das paredes não é importante. Você também pode considerá-lo infinito, para que a caixa seja um orifício retangular em um bloco de informações. O resultado seria o mesmo que qualquer outro valor para a espessura da parede. Exceto se você pretende dobrar / enganar as regras, quebrando fisicamente, distorcendo ou cortando a caixa ou a esfera, ou faça algo realmente estranho.
Victor Stafusa

3
@DarrenStone As caixas só têm espessura para fins de uma bela imagem. O problema lida com dimensões interiores.
Kendall Frey

Respostas:


21

Adiante

Por favor, encontre, abaixo, uma esfera fora da caixa.

A "esfera" é a função de computação de volume f. Os casos de teste de referência compõem a "caixa".

                     ( 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

Resultado:

0. 
0.523598775598299 
0.261799387799149 
0.279345334323962 
0.0654299441440212 

5

Java - baseado em número inteiro

Este programa não usa pi e não chama nenhuma função externa - nem mesmo o sqrt. Ele utiliza apenas aritmética simples - +, -, *e /. Além disso, além de uma etapa de dimensionamento, funciona exclusivamente com números inteiros. Basicamente, divide a esfera em pequenos cubos e conta os que estão fora da caixa.

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));
    }
}

Resultado:

0.0
0.5235867850933005
0.26178140856157484
0.27938608275528054
0.06542839088004015

Nesta forma, o programa requer mais de 2 GB de memória (funciona -Xmx2300maqui) e é muito lento. Ele usa a memória para pré-calcular um monte de raízes quadradas (aritmeticamente); não é realmente necessário, mas sem isso seria MUITO mais lento. Para melhorar as necessidades e a velocidade da memória, reduza o valor da MINconstante (que diminuirá a precisão).


2

Python 2 (abordagem baseada em matriz)

Ele cria uma matriz de matrizes com valores de verdade se um quadrado específico nessa grade estiver dentro do círculo ou fora do círculo. Deve ficar mais preciso quanto maior o círculo que você desenhar. Em seguida, ele seleciona uma área abaixo ou acima de uma determinada linha e conta a quantidade de quadrados que pertencem ao círculo e divide-os pela quantidade de quadrados que estão no círculo inteiro.

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, fórmula de tampa esférica

Esta versão emitirá um aviso de tempo de execução em alguns casos, mas ainda gera a resposta correta.

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))

Para mais 11 caracteres, posso me livrar do aviso.

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))

Aqui estão os casos de teste executados na versão 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

Mesmo que este não é o golfe código, você pode encurtar import numpy as na from numpy import*e tirar todo o n.seu código.
Timtech

@ Timtech Obrigado pelo aviso e sugestão.
precisa saber é o seguinte

1

Mathematica

Usando integração numérica com limites adequados.

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

Implementação de referência - 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);
        }
    }
}

Resultado:

0
0.523598775598299
0.261799387799149
0.279345334323962
0.0654299441440212

Eu não entendo esses resultados. O primeiro é obviamente 0. O segundo não tem altura, de modo que deve ser 1. O terceiro pode abrigar a bola, e exatamente metade dela está acima dela (a resposta deve ser 0,5). A caixa no caso 4 é um pouco pequena ou pequena, então fica em cima da caixa. A resposta deve ser um pouco maior que 0,5. A resposta para a última deve ser> 0,5, pois a largura / comprimento não é suficiente para encaixar a bola dentro.
precisa saber é o seguinte

@ Sumurai8 "Saída: o volume total ( não a porcentagem ) da esfera fora da caixa."
Kendall Frey

0

Rubi

Vamos ver ...
Se a caixa estiver totalmente dentro, largura> diâmetro; comprimento> diâmetro e altura> diâmetro.
Essa deve ser a primeira verificação a ser executada.

Se estiver no fundo, então w> d; l> deh V=(pi*h^2 /3)*(3r-h)Então, nesse caso, apenas obtemos a altura e a percorremos.

Se estiver travado, usamos uma fórmula semelhante ( V=(pi*h/6)*(3a^2 + h^2)). De fato, nossa fórmula anterior é baseada nessa! Basicamente, usamos isso, e a é simplesmente o menor de w e l. (dica, podemos obter altura fazendo h=r-a)

Agora o código!

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

Nota ** Eu não testei muito, então um erro pode ter surgido, se alguém perceber um, diga!
A matemática é sólida embora.
Versão mais curta:

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)])}

(Agora eu tenho certeza que obter h para a v2 é feito de maneira diferente, mas vou corrigi-lo mais tarde.


Agradável. Esse código lê claramente. Mas você tem certeza sobre a seguinte declaração? "podemos obter altura fazendo h=r-a" Eu estava lendo as fórmulas de tampa esférica , e o diagrama não sugere um relacionamento tão simples. Vou fazer outra leitura.
Darren Pedra

@ DarrenStone Agora que olho para trás, não tenho certeza. Estou extraordinariamente triste / exausto, mas de qualquer forma, é muito fácil de corrigir!

Tenho quase certeza de que a = wi > le ? le : wideve funcionar. Caso contrário, você tem um bug.
Konrad Borowski

a = wi>le?le:winão funcionou. Eu acho que é porque estou executando o git ruby ​​(desenvolvedor 2.2), pode ter dito desequilíbrio.

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;
}

Meu código encontra o volume do sólido de rotação do gráfico de uma parte de um semicírculo. pdbdmantém a distância linear da projeção de um ponto na superfície da esfera que toca o lábio da caixa com o diâmetro da esfera que, se estendida, seria normal ao fundo da caixa. As duas expressões que contêm M_PIsão basicamente o anti-derivado da integral de pi * -(x^2)+2rxem relação a x (onde x é uma medida do comprimento ao longo do diâmetro acima mencionado através da esfera e onde r é o raio da esfera) avaliado em uma pdbdou a diferença do diâmetro da esfera e da profundidade da caixa, dependendo do caso específico que ocorre com as diferentes dimensões.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.