Мислення поза коробкою


16

Ви намагаєтесь помістити кулю в 5-сторонній ящик, але іноді вона не вміщується повністю. Напишіть функцію, щоб обчислити, яка частина сфери знаходиться поза межами поля.

Можливі 3 можливі ситуації:

  • Куля повністю вписується в коробку. Відповідь буде 0.
  • Куля сідає на обід коробки. Відповідь складе більше половини загального обсягу.
  • Куля сидить на дні коробки.

Ви можете побачити кожну ситуацію тут:

Зображення

Ви повинні написати програму або функцію, щоб обчислити це значення принаймні до 4 значущих цифр.

Введення: 4 невід’ємні реальні цифри у будь-якому зручному форматі * - ширина, довжина, глибина коробки (внутрішні вимірювання) та діаметр сфери.

Вихід: 1 негативне реальне число у використаному форматі * - загальний обсяг (не відсоток) сфери поза полем.

* повинні бути конвертовані в / з десяткових рядків

Вам рекомендується максимально обмежити використання тригонометрії.

Це конкурс популярності, тому думайте поза межами!


будь-які приклади випадків, будь ласка?
mniip

1
Чи можна вважати , або стінка коробки нескінченно тонкої або розміри дані внутрішніх розміри? :)
Даррен Стоун

Які максимальні значення для входів?
Блендер

@DarrenStone Я думаю, що товщина стінок неважлива. Ви також можете вважати це нескінченним, тому коробка буде прямокутним отвором у цілому блоці. Результат буде таким же, як і будь-яке інше значення для товщини стіни. За винятком випадків, коли ви маєте намір зігнути / обдурити правила, фізично порушуючи, перекручуючи або нарізаючи коробку або сферу, або роблячи щось дійсно дивне.
Віктор Стафуса

3
@DarrenStone Коробки мають товщину лише для приємного зображення. Проблема стосується розмірів інтер'єру.
Кендалл Фрей

Відповіді:


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

У такому вигляді програмі потрібно більше 2 Гб оперативної пам’яті (працює -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 nдо from numpy import*і забрати все з n.вашого коду.
Timtech

@Timtech Дякую за голову та пропозицію.
користувач2487951

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 "Вихід: загальний об'єм ( не відсоток ) сфери поза полем."
Кендалл Фрей

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

(Тепер я точно знаю, що отримання h для v2 робиться інакше, але я це виправлю пізніше.


Приємно. Цей код чітко читається. Але ви впевнені в наступному твердженні? "ми можемо досягти висоти, роблячи h=r-a" Я просто читав формули сферичної шапки , і схема не передбачає такого простого відношення. Я ще раз прочитаю.
Даррен Стоун

@DarrenStone Тепер, коли я озираюся назад, я не впевнений. Я надзвичайно втомлений / виснажений, але в будь-якому випадку, це дуже легко виправити!

Я майже впевнений, що a = wi > le ? le : wiмає працювати. Інакше у вас помилка.
Конрад Боровський

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або різниця діаметру сфери та глибини коробки залежно від конкретного випадку, який відбувається з різними розмірами.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.