Berpikir di luar kotak


16

Anda mencoba memasukkan bola ke dalam kotak 5 sisi, tetapi terkadang bola itu tidak sepenuhnya cocok. Tulis fungsi untuk menghitung seberapa banyak bola di luar (di atas tepi) kotak.

Ada 3 kemungkinan situasi:

  • Bola itu benar-benar pas di dalam kotak. Jawabannya adalah 0.
  • Bola itu berada di tepi kotak. Jawabannya akan lebih dari setengah dari total volume.
  • Bola itu terletak di bagian bawah kotak.

Anda dapat melihat setiap situasi di sini:

Gambar

Anda harus menulis sebuah program atau fungsi untuk menghitung nilai ini setidaknya untuk 4 digit signifikan.

Input: 4 bilangan real non-negatif dalam format apa pun yang nyaman * - lebar, panjang, kedalaman kotak (pengukuran interior), dan diameter bola.

Output: 1 bilangan real non-negatif dalam format yang dapat digunakan * - volume total (bukan persentase) bola di luar kotak.

* harus dapat dikonversi ke / dari string desimal

Anda dianjurkan untuk membatasi penggunaan trigonometri sebanyak mungkin.

Ini adalah kontes popularitas, jadi pikirkan di luar kotak!


ada contoh kasus tolong?
mniip

1
Dapat kita asumsikan baik dinding kotak yang tak terhingga tipis atau dimensi yang diberikan adalah dimensi interior? :)
Darren Stone

Berapa nilai maksimum untuk input?
Blender

@ DarrenStone Saya pikir ketebalan dinding tidak penting. Anda bisa menganggapnya tidak terbatas juga, jadi kotak itu akan menjadi lubang persegi panjang di blok infinte. Hasilnya akan sama dengan nilai lain untuk ketebalan dinding. Kecuali jika Anda bermaksud membengkokkan / menipu aturan dengan secara fisik melanggar, mendistorsi atau mengiris kotak atau bola, atau melakukan sesuatu yang sangat aneh.
Victor Stafusa

3
@ DarrenStone Kotak-kotak hanya memiliki ketebalan untuk keperluan gambar yang bagus. Masalahnya berkaitan dengan dimensi interior.
Kendall Frey

Jawaban:


21

Keempat

Silakan temukan, di bawah ini, sebuah bola di luar kotak.

"Bola" adalah fungsi komputasi volume f. Kotak uji referensi menyusun "kotak".

                     ( 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

Keluaran:

0. 
0.523598775598299 
0.261799387799149 
0.279345334323962 
0.0654299441440212 

5

Berbasis Java - integer

Program ini tidak menggunakan pi dan tidak memanggil fungsi eksternal apa pun - bahkan bukan sqrt. Hanya menggunakan aritmatika sederhana - +, -, *dan /. Selain itu, selain langkah penskalaan, ini bekerja secara eksklusif dengan bilangan bulat. Ini pada dasarnya membagi bola menjadi kubus kecil dan menghitung yang ada di luar kotak.

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

Keluaran:

0.0
0.5235867850933005
0.26178140856157484
0.27938608275528054
0.06542839088004015

Dalam bentuk ini, program ini membutuhkan lebih dari 2GB memori (berfungsi dengan di -Xmx2300msini) dan cukup lambat. Ia menggunakan memori untuk menghitung ulang sekelompok akar kuadrat (secara hitung); itu tidak benar-benar diperlukan, tetapi tanpa itu akan menjadi BANYAK lebih lambat. Untuk meningkatkan kebutuhan dan kecepatan memori, kurangi nilai MINkonstanta (yang akan mengurangi keakuratannya).


2

Python 2 (pendekatan berbasis array)

Ini menciptakan array array dengan nilai kebenaran jika kotak tertentu di dalam kisi itu berada di dalam lingkaran atau di luar lingkaran. Seharusnya semakin tepat lingkaran yang Anda gambar. Itu kemudian memilih salah satu area di bawah atau di atas baris tertentu dan menghitung jumlah kotak yang menjadi milik lingkaran dan membaginya dengan jumlah kotak yang ada di seluruh lingkaran.

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 Topi Bulat

Versi ini akan memberikan peringatan runtime dalam beberapa kasus, tetapi tetap menampilkan jawaban yang benar.

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

Untuk 11 karakter lebih, saya bisa menghilangkan peringatan.

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

Berikut adalah kasus uji yang dijalankan pada versi 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

Meskipun ini bukan kode golf, Anda dapat mempersingkat import numpy as nuntuk from numpy import*dan mengambil semua n.dalam kode Anda.
Timtech

@Timtech Terima kasih atas saran dan sarannya.
user2487951

1

Mathematica

Menggunakan integrasi numerik dengan batas yang tepat.

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

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

Keluaran:

0
0.523598775598299
0.261799387799149
0.279345334323962
0.0654299441440212

Saya tidak mengerti hasil ini. Yang pertama jelas 0. Yang kedua tidak memiliki tinggi, sehingga yang satu harus 1. Yang ketiga bisa menampung bola, dan setengahnya tepat di atasnya (jawabannya harus 0,5). Kotak dalam kasus 4 hanya sedikit ke kecil, sehingga terletak di atas kotak. Jawabannya harus lebih dari 0,5. Jawaban untuk yang terakhir harus> 0,5, karena lebar / panjangnya tidak cukup untuk memasukkan bola ke dalam.
Sumurai8

@ Sumurai8 "Output: volume total ( bukan persentase ) dari bola di luar kotak."
Kendall Frey

0

Rubi

Mari kita lihat ...
Jika kotak itu sepenuhnya di dalam, maka lebarnya> diameter; panjang> diameter dan tinggi> diameter.
Itu harus menjadi cek pertama yang harus dijalankan.

Jika duduk di bawah, maka w> d; l> d dan h V=(pi*h^2 /3)*(3r-h)Jadi dalam hal ini, Kami hanya mendapatkan ketinggian dan menjalankannya melalui itu.

Jika macet, kami menggunakan rumus yang sama ( V=(pi*h/6)*(3a^2 + h^2)). Sebenarnya formula kami sebelumnya didasarkan pada formula ini! Pada dasarnya, kita menggunakannya, dan a hanyalah yang lebih kecil dari w dan l. (Petunjuk, kita bisa mendapatkan tinggi badan dengan melakukan h=r-a)

Sekarang kodenya!

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

Catatan ** Saya tidak mengujinya terlalu banyak, jadi kesalahan mungkin telah merayap masuk, jika ada yang memperhatikan, beri tahu!
Matematika itu solid.
Versi lebih pendek:

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

(Sekarang saya tahu pasti bahwa mendapatkan h untuk v2 dilakukan secara berbeda, tetapi saya akan memperbaikinya nanti.


Bagus. Kode itu terbaca dengan jelas. Tapi apakah Anda yakin dengan pernyataan berikut? "Kita bisa mendapatkan tinggi dengan melakukan h=r-a" Saya baru saja membaca pada rumus topi bulat , dan diagram tidak menyarankan hubungan yang begitu sederhana. Saya akan membacanya lagi.
Darren Stone

@ DarrenStone Sekarang saya melihat ke belakang saya tidak yakin. Saya sangat lelah / lelah, tetapi bagaimanapun juga, sangat mudah untuk ditambal!

Saya hampir pasti a = wi > le ? le : wiharus bekerja. Jika tidak, Anda memiliki bug.
Konrad Borowski

a = wi>le?le:witidak bekerja. Saya menduga itu karena saya menjalankan git ruby ​​(2.2 developer), mungkin dikatakan ketidakseimbangan.

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

Kode saya menemukan volume padatan rotasi grafik sebagian setengah lingkaran. pdbdmemegang jarak linier proyeksi titik pada permukaan bola yang menyentuh bibir kotak dengan diameter bola yang, jika diperpanjang, akan normal ke bagian bawah kotak. Dua ekspresi yang mengandung M_PIpada dasarnya adalah anti-turunan dari integral pi * -(x^2)+2rxsehubungan dengan x (di mana x adalah ukuran panjang sepanjang diameter yang disebutkan di atas melalui bola dan di mana r adalah jari-jari bola) dievaluasi pada salah satu pdbdatau perbedaan diameter bola dan kedalaman kotak tergantung pada kasus khusus yang terjadi dengan dimensi yang berbeda.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.