ในบรรดาโจทย์ปี 2008 คิดว่าข้อนี้น่าจะยากที่สุดครับ แอบเถื่อนนิดหน่อยตรงที่มันใช้ Math พอสมควร ใจความหลักของโจทย์ข้อนี้คือ “จะหาพื้นที่ที่ตัดกันระหว่างวงกลมกับสี่เหลี่ยมได้ยังไง” ซึ่งมันก็มีหลายวิธี
- ทำ Computer Integration วิธีนี้ผมใช้ตอนปีก่อน อารมณ์ประมาณซอยเป็นสี่เหลี่ยมคางหมูหลายๆอันให้ถี่ๆ ก็จะใช้ประมาณพื้นที่ได้ โจทย์บอกว่าคำตอบต้องละเอียดถึง 1e-6 ก็ต้องแบ่งให้ถี่ๆแบบสัมพันธ์หน่อย เหมือนวิธีนี้จะเรียกผลรวมรีมันด์อะไรซักอย่าง จำไม่ได้ล่ะ (ได้แคลคูลัส C)
- ทำ Integrate รูปปิด ประมาณว่าหาสูตรคำนวณพื้นที่นั่นเอง หลังจากนั้นก็เอาขอบเขตมาแทนค่าพร้อมกับตัดเติมลบอีกนิดหน่อย ก็จะได้พื้นที่ออกมาเลย การ Integrate สมการวงกลม (x^2 + y^2 = r^2) มันทำยาก ใช้ Tool พวกที่ช่วยทำ Integrate ให้ได้ แล้วค่อยมาเอาแทนค่า (รายละเอียดเต็มๆเชิญกระมู้นี้)

- อีกวิธีใช้เรขาคณิตวิเคราะห์ธรรมดา! คำนวณพื้นที่ส่วนที่รู้แล้วด้วยวิธีปกติก่อน ส่วนที่มันเป็นโค้งๆก็ใช้วิธีการหาพื้นที่ของ segment แล้วลบออกด้วยพื้นที่สามเปลี่ยม ก็จะได้เฉพาะพื้นที่ส่วนที่เป็นโค้งๆสีเหลือง เอามาคำนวณต่อได้ ครั้งนี้ใช้วิธีนี้
ไปที่โค้ด Python ขอสารภาพว่าดีบั๊กอยู่นานพอควร ไม่รู้ตอนสอบปีก่อนรอด Large test case ข้อนี้มาได้ไง ><’’
โค้ดน่าเกลียดไปหน่อย ซ้อนกันหลายบล็อคเกิน
import math
def calculate_segment(R,x1,y1,x2,y2):
ang1 = math.atan(y1/x1)
ang2 = math.atan(y2/x2)
ang = math.fabs(ang1 - ang2)
area = (ang/math.pi/2)*math.pi*R**2
cord = math.sqrt((x1-x2)**2 + (y1-y2)**2)
pie = math.cos(ang/2)*R*cord/2
return area - pie
if __name__ == '__main__':
#in_filename = "C-small-practice.in"
#in_filename = "C-dummy.in"
in_filename = "C-large-practice.in"
#out_filename = "C-small.out"
out_filename = "C-large.out"
in_file = open(in_filename, 'r')
num_cases = int(in_file.readline())
out_file = open(out_filename, 'w')
for c in range(0,num_cases):
f, R, t, r, g = [float(x) for x in in_file.readline().split(' ')]
r = r + f
g = g - 2*f
t = t + f
x1 = r
y1 = r
# Is the interested point inside the circle
is_inside = lambda x,y : (x**2 + y**2) <= (R-t)**2
# Get y from x, or get x from y
get_pair = lambda x : math.sqrt((R-t)**2 - x**2)
if g > 0.0:
area = 0.0
while x1 <= R-t:
while y1 <= R-t:
x2 = x1 + g
y2 = y1 + g
if is_inside(x1,y1):
if is_inside(x2,y2):
# Full rectangle is inside
area = area + (x2-x1)*(y2-y1)
else:
x1_y2_in = is_inside(x1,y2)
x2_y1_in = is_inside(x2,y1)
if x1_y2_in and x2_y1_in:
xt = get_pair(y2)
yt = get_pair(x2)
area = area + (x2-x1)*(y2-y1)
area = area - (x2-xt)*(y2-yt)/2
area = area + calculate_segment(R-t,xt,y2,x2,yt)
elif x1_y2_in and not x2_y1_in:
xt2 = get_pair(y2)
xt1 = get_pair(y1)
area = area + (xt2 + xt1 - 2*x1)*(y2-y1)/2
area = area + calculate_segment(R-t,xt2,y2,xt1,y1)
elif not x1_y2_in and x2_y1_in:
yt1 = get_pair(x1)
yt2 = get_pair(x2)
area = area + (yt1 + yt2 - 2*y1)*(x2-x1)/2
area = area + calculate_segment(R-t,x1,yt1,x2,yt2)
else:
yt = get_pair(x1)
xt = get_pair(y1)
area = area + (yt-y1)*(xt-x1)/2
area = area + calculate_segment(R-t,x1,yt,xt,y1)
y1 = y1 + g + 2*r
x1 = x1 + g + 2*r
y1 = r
all_area = math.pi*R*R/4
prob = (all_area - area)/all_area
else:
prob = 1.0
out_file.write("Case #%d: %f\n" % (c+1, prob))
out_file.close()
Tags: google, code jam, python, math