【ちょっとづつAtCode】ABC191 D – Circle Lattice Points

ちょっとづつAtCoder

引用

(引用)

問題文
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使うしかないのかなぁ

コメント

タイトルとURLをコピーしました