引用
(引用)
問題文
2 次元平面上に中心 (X,Y) 、半径 R の円があります。
この円の内部または周上にある格子点 (x,y座標がともに整数である点) の個数を求めてください。
制約
|X|≤105
|Y|≤105
0<R≤105
X,Y,R
は高々小数第 4 位まで与えられる
AtCoder Beginner Contest 191 D – Circle Lattice Pointsより引用
入力
入力は以下の形式で標準入力から与えられる。
X Y R
出力
答えを出力せよ。
入力例 1
0.2 0.8 1.1
出力例 2
3
以下のような円になります。赤く印の付いた点が、この円の内部または周上にある格子点です。
考えてみました①
まず円の一番外から下ろした足〜足までの中で、整数の緑点〜緑点までをforでまわす
3平方の定理で h = √(R^2 – (X-i)^2)
(Y + h)の端数を捨てた格子点(math.floor)〜(Y – h)の端数を捨てた格子点(math.ceil) + 1
をカウント
X, Y, R = map(float,input().split())
count = 0
import math
for i in range(math.ceil(X-R), math.floor(X+R+1)):
h = (R**2 - (X-i)**2) ** 0.5
g = math.floor(Y+h)-math.ceil(Y-h)+1
count += g
print(count)
3つほどWA
その後、解説にあった「10000倍にして誤差を減らす」
考えてみました②
10000倍して、//10000でカウント(ただし、//10000の場合は全部math.floorになる)
①円の左右端の点は、gが0になってしまうので、左右端が格子点になる場合は+1
②縦に格子点をカウントしていく過程で、Y+hがy軸格子点でもそのまま、Y-hがy軸格子点の場合は+1補正
この二つに注意して
X, Y, R = [float(x)*10000 for x in input().split()]
count = 0
import math
for i in range(math.ceil((X-R)/10000), math.floor((X+R+10000)/10000)):
h = math.sqrt(R**2 - (X-i*10000)**2)
# 円の左右端の点は、gが0になってしまうので、左右端が格子点になる場合は+1
if abs(X-i*10000) == R and Y % 10000 == 0:
g = (Y + h) // 10000 - (Y - h) // 10000 + 1
#縦に格子点をカウントしていく過程で、Y+hがy軸格子点でもそのまま、Y-hがy軸格子点の場合は+1補正
elif (Y - h) % 10000 == 0:
g = (Y + h) // 10000 - (Y - h) // 10000 + 1
else:
g = (Y + h) // 10000 - (Y - h) // 10000
count += g
print(int(count))
WAが4つ
(もしかして、もっと精度が悪い!?って思って)10000⇨100000にしてみたけど
WAが2つ
100000⇨1000000にしてみたらWAが4つ(笑)
もうわからん
考えてみました③
ほかの人のを参考にDecimalを使うことに
#円の内部の格子点
import math
from decimal import Decimal as De
#文字列&デサマル(十進法の)化
X, Y, R = [De(str(a)) for a in input().split()]
count = 0
for i in range(math.ceil(X-R), math.floor(X+R+1)):
h = (R**2 - (X-i)**2).sqrt()#**0.5よりも、.sqrt()「square root化」
g = math.floor(Y+h)-(math.ceil(Y-h))+1
count += g
print(count)
ずるい位あっさり解決したのですけど、やっぱり小数からむとDecimal使うしかないのかなぁ
コメント