คิดนอกกรอบ


16

คุณกำลังพยายามใส่ทรงกลมลงในกล่องแบบ 5 ด้าน แต่บางครั้งก็ไม่พอดี เขียนฟังก์ชันเพื่อคำนวณว่าทรงกลมอยู่นอกกรอบ (เหนือขอบ) กล่องเท่าใด

มี 3 สถานการณ์ที่เป็นไปได้:

  • ทรงกลมพอดีในกล่อง คำตอบจะเป็น 0
  • ทรงกลมตั้งอยู่บนขอบของกล่อง คำตอบจะมากกว่าครึ่งหนึ่งของปริมาณทั้งหมด
  • ทรงกลมตั้งอยู่ที่ด้านล่างของกล่อง

คุณสามารถดูแต่ละสถานการณ์ได้ที่นี่:

ภาพ

คุณต้องเขียนโปรแกรมหรือฟังก์ชั่นเพื่อคำนวณค่านี้ให้เป็นตัวเลขที่มีนัยสำคัญอย่างน้อย 4 หลัก

อินพุต: ตัวเลขจริงที่ไม่ใช่ลบ 4 ตัวในรูปแบบใดก็ได้ที่สะดวก * - ความกว้างความยาวความลึกของกล่อง (การวัดภายใน) และเส้นผ่านศูนย์กลางของทรงกลม

เอาต์พุต: 1 จำนวนจริงที่ไม่เป็นลบในรูปแบบที่ใช้งานได้ * - ปริมาตรรวม (ไม่ใช่เปอร์เซ็นต์) ของทรงกลมที่อยู่นอกกล่อง

* ต้องแปลงเป็น / จากสตริงทศนิยม

คุณควร จำกัด การใช้ตรีโกณมิติให้มากที่สุด

นี่คือการประกวดความนิยมดังนั้นคิดนอกกรอบ!


กรณีตัวอย่างใดโปรด
mniip

1
เราสามารถสมมติว่าผนังของกล่องมีขนาดเล็กหรือขนาดที่กำหนดเป็นขนาดภายในได้หรือไม่? :)
Darren Stone

ค่าสูงสุดสำหรับอินพุตคืออะไร?
Blender

@ DarrenStone ฉันคิดว่าความหนาของผนังไม่สำคัญ คุณสามารถพิจารณาว่ามันไม่มีที่สิ้นสุดเช่นกันดังนั้นกล่องจะเป็นรูสี่เหลี่ยมในบล็อก infinte ผลที่ได้จะเหมือนกับค่าอื่น ๆ สำหรับความหนาของผนัง ยกเว้นถ้าคุณตั้งใจที่จะงอ / โกงกฎโดยการทำลายร่างกายบิดเบี้ยวหรือแบ่งกล่องหรือทรงกลมหรือทำสิ่งที่แปลกจริงๆ
Victor Stafusa

3
@DarrenStone กล่องมีความหนาเท่านั้นสำหรับวัตถุประสงค์ของภาพที่ดี ปัญหาเกี่ยวข้องกับมิติภายใน
Kendall Frey

คำตอบ:


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

ในรูปแบบนี้โปรแกรมต้องการหน่วยความจำมากกว่า 2GB (ทำงานได้-Xmx2300mที่นี่) และทำงานช้ากว่าที่กำหนด มันใช้หน่วยความจำในการคำนวณกลุ่มของรากที่สอง (คำนวณ); มันไม่จำเป็นจริงๆ แต่ถ้าไม่มีมันจะช้ากว่ามาก เพื่อปรับปรุงความต้องการและความเร็วของหน่วยความจำให้ลดค่าของค่าMINคงที่ (ซึ่งจะลดความแม่นยำลง)


2

Python 2 (วิธี Array-based)

มันสร้างอาร์เรย์ของอาร์เรย์ที่มีค่าความจริงหากตารางเฉพาะในตารางนั้นอยู่ในวงกลมหรือนอกวงกลม ควรให้แม่นยำยิ่งขึ้นเท่าที่คุณจะวาดวงกลม จากนั้นจะเลือกพื้นที่ด้านล่างหรือเหนือแถวใดแถวหนึ่งแล้วนับจำนวนสี่เหลี่ยมที่เป็นของวงกลมแล้วหารด้วยจำนวนสี่เหลี่ยมที่อยู่ในวงกลมทั้งหมด

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 สูตร Cap ทรงกลม

รุ่นนี้จะส่งสัญญาณเตือนรันไทม์ในบางกรณี แต่ยังคงเอาท์พุทคำตอบที่ถูกต้อง

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

มาติกา

การใช้การรวมเชิงตัวเลขกับขีด จำกัด ที่เหมาะสม

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 8

@ Sumurai8 "เอาต์พุต: ปริมาตรรวม ( ไม่ใช่เปอร์เซ็นต์ ) ของทรงกลมนอกกรอบ"
Kendall Frey

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" ฉันเพิ่งอ่านสูตรหมวกทรงกลมและแผนภาพไม่ได้แนะนำความสัมพันธ์ที่เรียบง่าย ฉันจะให้อีกอ่าน
Darren Stone

@DarrenStone ตอนนี้ฉันมองย้อนกลับไปฉันไม่แน่ใจ ฉันลง / เหนื่อยเป็นพิเศษ แต่อย่างใดมันง่ายมากที่จะปะ!

ฉันเกือบจะแน่ใจว่าa = wi > le ? le : wiควรจะทำงาน มิฉะนั้นคุณจะมีข้อบกพร่อง
Konrad Borowski

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หรือ ความแตกต่างของเส้นผ่าศูนย์กลางทรงกลมและความลึกของกล่องขึ้นอยู่กับกรณีเฉพาะที่เกิดขึ้นกับมิติที่แตกต่างกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.