pensare fuori dagli schemi


16

Stai cercando di inserire una sfera in una scatola a 5 lati, ma a volte non si adatta completamente. Scrivi una funzione per calcolare la quantità di sfera esterna (sopra il bordo) della scatola.

Esistono 3 possibili situazioni:

  • La sfera si inserisce completamente nella scatola. La risposta sarà 0.
  • La sfera si trova sul bordo della scatola. La risposta sarà più della metà del volume totale.
  • La sfera si trova sul fondo della scatola.

Puoi vedere ogni situazione qui:

Immagine

È necessario scrivere un programma o una funzione per calcolare questo valore su almeno 4 cifre significative.

Input: 4 numeri reali non negativi in ​​qualsiasi formato sia conveniente * - larghezza, lunghezza, profondità della scatola (misure interne) e diametro della sfera.

Output: 1 numero reale non negativo in un formato utilizzabile * - il volume totale (non la percentuale) della sfera fuori dagli schemi.

* deve essere convertibile in / da una stringa decimale

Siete incoraggiati a limitare il più possibile l'uso della trigonometria.

Questo è un concorso di popolarità, quindi pensa fuori dagli schemi!


qualche esempio per favore?
mniip,

1
Possiamo presumere che le pareti della scatola siano infinitamente sottili o le dimensioni indicate siano dimensioni interne? :)
Darren Stone,

Quali sono i valori massimi per gli ingressi?
Blender

@DarrenStone Penso che lo spessore delle pareti non sia importante. Potresti considerarlo anche infinito, quindi la scatola sarebbe un buco rettangolare in un blocco infinte. Il risultato sarebbe lo stesso di qualsiasi altro valore per lo spessore della parete. Tranne se si intende piegare / imbrogliare le regole rompendo, distorcendo o tagliando fisicamente la scatola o la sfera o facendo qualcosa di veramente strano.
Victor Stafusa,

3
@DarrenStone Le scatole hanno spessore solo ai fini di una bella foto. Il problema riguarda le dimensioni interne.
Kendall Frey,

Risposte:


21

Via

Di seguito, trovi una sfera fuori dagli schemi.

La "sfera" è la funzione di calcolo del volume f. I casi di test di riferimento compongono la "casella".

                     ( 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

Produzione:

0. 
0.523598775598299 
0.261799387799149 
0.279345334323962 
0.0654299441440212 

5

Java - basato su numeri interi

Questo programma non usa pi e non chiama alcuna funzione esterna - nemmeno sqrt. Si utilizza solo semplice aritmetica - +, -, *e /. Inoltre, oltre a una fase di ridimensionamento, funziona esclusivamente con numeri interi. In pratica divide la sfera in piccoli cubetti e conta quelli che sono fuori dagli schemi.

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

Produzione:

0.0
0.5235867850933005
0.26178140856157484
0.27938608275528054
0.06542839088004015

In questa forma, il programma richiede più di 2 GB di memoria (funziona -Xmx2300mqui) ed è abbastanza lento. Usa la memoria per precalcolare un gruppo di radici quadrate (aritmeticamente); non è davvero necessario, ma senza quello sarebbe MOLTO più lento. Per migliorare sia le esigenze di memoria che la velocità, ridurre il valore della MINcostante (che ridurrà comunque la precisione).


2

Python 2 (approccio basato su array)

Crea una matrice di matrici con valori di verità se un quadrato specifico in quella griglia si trova all'interno del cerchio o all'esterno del cerchio. Dovrebbe essere più preciso quanto più grande è il cerchio che stai disegnando. Quindi seleziona un'area al di sotto o al di sopra di una determinata riga e conta la quantità di quadrati che appartiene al cerchio e lo divide per la quantità di quadrati che si trovano nell'intero cerchio.

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, Formula con tappo sferico

Questa versione genererà un avviso di runtime in alcuni casi, ma restituirà comunque la risposta corretta.

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

Per altri 11 caratteri, posso liberarmi dell'avvertimento.

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

Ecco i casi di test eseguiti sulla versione 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

Anche se questo non è il codice di golf, si può abbreviare import numpy as nper from numpy import*e portare via tutto il n.nel codice.
Timtech,

@Timtech Grazie per il testa a testa e il suggerimento.
user2487951

1

matematica

Utilizzo dell'integrazione numerica con limiti adeguati.

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

Implementazione di riferimento - 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);
        }
    }
}

Produzione:

0
0.523598775598299
0.261799387799149
0.279345334323962
0.0654299441440212

Non capisco questi risultati. Il primo è ovviamente 0. Il secondo non ha altezza, quindi uno dovrebbe essere 1. Il terzo può ospitare la palla, e esattamente la metà di essa è sopra di essa (la risposta dovrebbe essere 0,5). La scatola nel caso 4 è solo un po 'piccola, quindi si appoggia sopra la scatola. La risposta dovrebbe essere un po 'più di 0,5. La risposta per l'ultima dovrebbe essere> 0,5, poiché la larghezza / lunghezza non è sufficiente per adattarsi alla palla all'interno.
Sumurai8,

@ Sumurai8 "Output: il volume totale ( non la percentuale ) della sfera fuori dagli schemi."
Kendall Frey,

0

Rubino

Vediamo ...
Se la scatola è completamente interna, quindi larghezza> diametro; lunghezza> diametro e altezza> diametro.
Questo dovrebbe essere il primo controllo da eseguire.

Se è seduto in fondo, allora w> d; l> d e h V=(pi*h^2 /3)*(3r-h)Quindi, in quel caso, prendiamo solo l'altezza e la attraversiamo.

Se è bloccato, usiamo una formula simile ( V=(pi*h/6)*(3a^2 + h^2)). In effetti la nostra formula precedente si basa su questa! Essenzialmente, lo usiamo e a è semplicemente il più piccolo di w e l. (suggerimento, possiamo ottenere l'altezza facendo h=r-a)

Ora il codice!

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 ** Non l'ho testato troppo, quindi potrebbe essersi verificato un errore, se qualcuno se ne accorge uno, dillo!
La matematica è solida però.
Versione più corta:

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

(Ora so per certo che ottenere h per v2 è fatto in modo diverso, ma lo risolverò in seguito.


Bello. Quel codice legge chiaramente. Ma sei sicuro della seguente affermazione? "possiamo ottenere l'altezza facendo h=r-a" Stavo solo leggendo le formule del cappuccio sferico e il diagramma non suggerisce una relazione così semplice. Lo darò un'altra lettura.
Darren Stone,

@DarrenStone Ora che guardo indietro non sono sicuro. Sono straordinariamente giù / sfinito, ma in entrambi i casi, è molto facile da rattoppare!

Sono quasi sicuro che a = wi > le ? le : widovrebbe funzionare. Altrimenti, hai un bug.
Konrad Borowski il

a = wi>le?le:winon ha funzionato. Immagino sia perché sto eseguendo git ruby ​​(sviluppatore 2.2), potrebbe aver detto squilibrio.

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

Il mio codice trova il volume del solido di rotazione del grafico di una parte di un semicerchio. pdbdmantiene la distanza lineare della proiezione di un punto sulla superficie della sfera che tocca il labbro della scatola con il diametro della sfera che, se esteso, sarebbe normale al fondo della scatola. Le due espressioni che contengono M_PIsono sostanzialmente l'anti-derivato dell'integrale pi * -(x^2)+2rxrispetto a x (dove x è una misura della lunghezza lungo il diametro sopra menzionato attraverso la sfera e dove r è il raggio della sfera) valutato in uno pdbdo la differenza del diametro della sfera e della profondità della scatola in base al caso particolare che si verifica con le diverse dimensioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.