Kutunun dışında düşünmek


16

Bir küreyi 5 taraflı bir kutuya sığdırmaya çalışıyorsunuz, ancak bazen tam olarak uymuyor. Kürenin ne kadarının kutunun dışında (kenarının üstünde) olduğunu hesaplamak için bir işlev yazın.

3 olası durum vardır:

  • Küre tamamen kutuya sığar. Cevap 0 olacaktır.
  • Küre kutunun kenarına oturur. Cevap toplam hacmin yarısından fazla olacaktır.
  • Küre kutunun altında oturur.

Her bir durumu burada görebilirsiniz:

görüntü

Bu değeri en az 4 önemli basamağa hesaplamak için bir program veya işlev yazmalısınız.

Girdi: Hangi formatta olursa olsun 4 negatif olmayan gerçek sayı * - genişlik, uzunluk, kutunun derinliği (iç ölçümler) ve kürenin çapı.

Çıktı: Kullanılabilir bir formatta 1 negatif olmayan gerçek sayı * - kutunun dışındaki kürenin toplam hacmi (yüzde değil).

* ondalık dizeye dönüştürülebilir

Trigonometri kullanımınızı mümkün olduğunca sınırlandırmanız önerilir.

Bu bir popülerlik yarışması, bu yüzden kutunun dışında düşünün!


herhangi bir örnek vaka lütfen?
Ocak'ta mniip

1
Varsayabiliriz ya kutunun duvarları ince sonsuz olan veya verilen boyutlar iç boyutları nelerdir? :)
Darren Stone

Girişler için maksimum değerler nelerdir?
Blender

@DarrenStone Duvar kalınlığının önemsiz olduğunu düşünüyorum. Sonsuz olarak da düşünebilirsiniz, bu yüzden kutu bir infinte blokta dikdörtgen bir delik olacaktır. Sonuç, duvar kalınlığı için herhangi bir diğer değerle aynı olacaktır. Kutuyu veya küreyi fiziksel olarak kırarak, bozarak veya dilimleyerek ya da gerçekten garip bir şey yaparak kuralları bükmek / aldatmak istiyorsanız.
Victor Stafusa

3
@DarrenStone Kutular sadece güzel bir resim için kalınlığa sahiptir. Sorun iç boyutlarla ilgilidir.
Kendall Frey

Yanıtlar:


21

ileri

Lütfen kutunun dışında bir küre bulun.

"Küre" hacim hesaplama fonksiyonudur f. Referans test senaryoları "kutuyu" oluşturur.

                     ( 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

Çıktı:

0. 
0.523598775598299 
0.261799387799149 
0.279345334323962 
0.0654299441440212 

5

Java - tamsayı tabanlı

Bu program pi kullanmaz ve herhangi bir harici işlevi çağırmaz - sqrt bile. Sadece basit aritmetik kullanır - +, -, *ve /. Ayrıca, bir ölçeklendirme aşaması dışında, yalnızca tamsayılarla çalışır. Temel olarak küreyi küçük küplere ayırır ve kutunun dışındakileri sayar.

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

Çıktı:

0.0
0.5235867850933005
0.26178140856157484
0.27938608275528054
0.06542839088004015

Bu formda, program 2GB'tan fazla bellek gerektirir ( -Xmx2300mburada çalışır ) ve yavaştır. Bir grup kare kökünü (aritmetik olarak) önceden hesaplamak için belleği kullanır; bu gerçekten gerekli değil, ama onsuz çok daha yavaş olurdu. Hem bellek ihtiyaçlarını hem de hızı iyileştirmek için MINsabitin değerini azaltın (bu doğruluk oranını azaltır).


2

Python 2 (Dizi tabanlı yaklaşım)

Bu ızgaradaki belirli bir kare dairenin içinde veya dairenin dışındaysa, doğruluk değerlerine sahip bir dizi dizi oluşturur. Çizdiğiniz daire ne kadar büyük olursa o kadar kesinleşmelidir. Daha sonra belirli bir satırın altındaki veya üstündeki bir alanı seçer ve daireye ait olan karelerin sayısını sayar ve bunu tüm dairenin içindeki karelere böler.

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, Küresel Kapak Formülü

Bu sürüm bazı durumlarda bir çalışma zamanı uyarısı gönderir, ancak yine de doğru yanıtı verir.

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 karakter daha için, uyarıdan kurtulabilirim.

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

İşte sürüm 1 üzerinde çalışan test senaryoları:

$ 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

Bu kod golf olmamasına rağmen, sen kısaltabilirsiniz import numpy as niçin from numpy import*ve tüm götürmek n.kodunuzda.
Timtech

@Timtech Uyarı ve öneri için teşekkürler.
user2487951

1

Mathematica

Uygun sınırlarla sayısal entegrasyon kullanma.

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

Referans Uygulaması - 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);
        }
    }
}

Çıktı:

0
0.523598775598299
0.261799387799149
0.279345334323962
0.0654299441440212

Bu sonuçları anlamıyorum. Birincisi açıkça 0'dır. İkincisinin yüksekliği yoktur, böylece biri 1 olmalıdır. Üçüncüsü topu barındırabilir ve tam yarısı bunun üzerindedir (cevap 0,5 olmalıdır). Durum 4'teki kutu biraz küçüktür, bu yüzden kutunun üstünde durur. Cevap 0,5'ten biraz daha fazla olmalıdır. Sonuncunun cevabı> 0,5 olmalıdır, çünkü genişlik / uzunluk topu içeri sokmak için yeterli değildir.
Sumurai8

@ Sumurai8 "Çıktı: kutunun dışındaki kürenin toplam hacmi ( yüzde değil )."
Kendall Frey

0

Yakut

Bakalım ...
Kutu tamamen içerideyse, genişlik> çap; uzunluk> çap ve yükseklik> çap.
Çalıştırmak için ilk kontrol bu olmalı.

Eğer altta oturuyorsa, w> d; l> d ve h V=(pi*h^2 /3)*(3r-h)Yani bu durumda, sadece yüksekliği elde edip içinden geçiyoruz.

Sıkışmışsa, benzer bir formül ( V=(pi*h/6)*(3a^2 + h^2)) kullanırız. Aslında önceki formülümüz buna dayanıyor! Esasen, bunu kullanıyoruz ve a sadece w ve l'den daha küçük olanıdır. (ipucu, yaparak yükseklik elde edebiliriz h=r-a)

Şimdi kod!

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

Not ** Çok fazla test etmedim, bu yüzden bir hata fark etmiş olabilir, biri fark ederse, söyleyin!
Matematik sağlam.
Kısa versiyon:

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

(Şimdi v2 için h almanın farklı yapıldığından eminim, ancak daha sonra düzeltirim.


Güzel. Bu kod açıkça okunuyor. Ancak aşağıdaki ifadeden emin misiniz? "yaparak yükseklik elde edebiliriz h=r-a" Sadece küresel başlık formüllerini okuyordum ve şema bu kadar basit bir ilişki önermiyor. Bir kez daha okuyacağım.
Darren Stone

@DarrenStone Şimdi geriye baktığımdan emin değilim. Olağanüstü bir şekilde aşağı / bitkinim, ama her iki durumda da, yama yapmak çok kolay!

Neredeyse a = wi > le ? le : wiişe yarayacağından eminim . Aksi takdirde, bir hata var.
Konrad Borowski

a = wi>le?le:wiişe yaramadı. Sanırım git ruby ​​(2.2 geliştirici) çalıştırıyorum, dengesizlik demiş olabilir.

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

Kodum, yarım dairenin bazı bölümlerinin grafiğinin dönme katı hacmini bulur. pdbdkürenin dudağına kutunun dudağına değen bir noktanın izdüşümünün, uzatılmışsa kutunun dibine göre normal olan küre çapına olan doğrusal mesafesini tutar. İçeren iki ifade M_PItemelde pi * -(x^2)+2rxx ile ilgili integralin anti-türevidir (burada x, küre boyunca yukarıda belirtilen çap boyunca uzunluğun bir ölçüsüdür ve burada r, kürenin yarıçapıdır) pdbdveya farklı boyutlarda meydana gelen özel duruma bağlı olarak küre çapının ve kutu derinliğinin farkı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.