Нестандартное мышление


16

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

Есть 3 возможных ситуации:

  • Сфера полностью помещается в коробку. Ответ будет 0.
  • Сфера сидит на краю коробки. Ответ будет более половины от общего объема.
  • Сфера сидит на дне коробки.

Вы можете увидеть каждую ситуацию здесь:

Образ

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

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

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

* должен быть преобразован в / из десятичной строки

Вам рекомендуется максимально ограничить использование тригонометрии.

Это конкурс популярности, так что думайте нестандартно!


какие-либо примеры случаев, пожалуйста?
Мниип

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 Спасибо за советы и предложения.
user2487951

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, так как ширина / длина не достаточны, чтобы поместиться внутри мяча.
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по й (где х является мерой длины вдоль упомянутого выше диаметра через сферу и где г-радиус сферы) оценивал на любом pdbdили разница диаметра сферы и глубины коробки в зависимости от конкретного случая, который происходит с различными размерами.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.