문제: https://school.programmers.co.kr/learn/courses/30/lessons/181187

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

문제설명 : 내원과 외원 사이의 점들의 갯수를 구해야한다.

사이에서의 각 픽셀(rectangle)이 내원이나 외원에 접하는 경우 (하기 그림, x =3 일때) 도 카운팅한다.

 

(그림 출처 : https://sasca37.tistory.com/320)

 

TC

r1 r2 Return
2 4 40
9 20 1008
10 20 952
999999 1000000 6281440
3 4 24
1 2 12

 

로직:

1. 사분표로 되있기에 1사분표의 갯수만 구하여서 1사분표 점 갯수 *4 할 것이다.

▶ 피타고라스 정리 x^2 + y^2 = r^2 을 활용한다.  => y^2 = r^2 - x^2;
▶ 주어지는 x, r에 의해 y 좌표를 알 수 있다. (y의 좌표는 픽셀 상단 우측 꼭짓점 기준으로 한다.)
▶ 구해진 y좌표가 소수점인 경우 외원은 내림으로 내원은 올림을 한다. 

▶ r1_y <= t <= r2_y 범위에서 t의 갯수를 구한다. => cnt = r2_y - r1_y + 1
   => 동적으로 최대 1,000,000 사이즈를 갖는 벡터를 만들면 기억공간이 많이 든다.[내원의 경우 원을 초과하는 x좌표의 y값을 0으로 초기화] 굳이 공간을 만들지 않고 조건문과 연산만으로 갯수를 구하자.   
▶한 축에 2개는 고정으로 접해있는 특징을 활용해,  1사분표의 점의 갯수(answer) = cnt(축의 점 갯수 제외) + 2 (축의 점 갯수) 

하기 반복문 조건문을 변경하여 축의 점 갯수를 고정식으로 더해줄 필요는 없다.
  ▷ 반례 )  x= 0 ; x < r2; ++x  //  r2이전의 내원이 x축에 접하는 것까지 계산됨. 이미  x =0에서 y축에 접하는 것을 계산 
  ▷ 정답 ) x = 1 ; x <= r2 ; ++x // 이 범위에서 온전히 하나의 축(x축)에서 접하는 외원과 내원의 갯수 2를 추출.

▶ (▷ 정답 조건문 적용)사분표의 특징을 활용해  answer = 1사분표의 점의 갯수(answer) * 4를 하면된다.

#include<bits/stdc++.h>
using namespace std;
long long solution(int R1, int R2) {
    long long r1 = (long long) R1; // * 연산 시 오버플로우 방지용.
    long long r2 = (long long) R2;
    long long answer = 0;
    //r2 까지 범위에서 x가 r1을 초과할 때 조건문.
    for(long long x = 1; x<= r2; ++x){ // 1사분면의 x축의 내원, 외원의 y 점까지 카운팅. (y축은 아님)
      long long r1_y = 0; 
      long long r2_y = 0;
      r2_y = floor(sqrt((r2 * r2) - (x * x)));  //올림, int형인 r1, r2를 각각 제곱하면 오버플로우 발생. long long으로 casting.
      if(x < r1) r1_y = ceil(sqrt((r1 * r1) - (x * x)));  // 조건문을 통해서 x가 내원 반지름 사이에 존재하는 경우 내원의 y값 내림
      int cnt= r2_y - r1_y + 1;
      answer += cnt;
    }
    return answer *= 4; //사분면이기에 위 1사분면 갯수 * 4
}

회고 : 도형에 대한 사고가 부족했다.

입력 값을 제곱 시 오버플로우가 발생할 것을 예상치 못했다. (TC 7 ~ 10 실패)

 

이번 문제는 힌트에 의해 풀게 됐지만, 다음에 동일한 유형이 나오면 손 쉽게 풀자.


 

실패 사례

첫번째 풀이

실패 원인 : (r1 ,r2) 가 (1,2) , (2,3) 을 통해 전체의 규칙을 찾으려는 시도를 했던 것 같다. 잘 못된 규칙이다. 

#include <string>
#include <vector>

using namespace std;
/*

(r1, r2)
r1 <= x < r2
for 문 x 번까지 t+= 8 * x;

t+4;

*/
long long solution(int r1, int r2) {
    long long answer = 0;
    for(int x = r1; x<r2;++x){
        answer+=(8*x);
    }
    answer+=4;
    return answer;
}

두번째 풀이

실패원인: 만일 둘다 내람차순 해서 총 외원의 픽셀갯수 - 총 내원의 픽셀 갯수를 하면 외원과 내원이 픽셀 상단 우측 꼭짓점에 각각 접했을 때 점이 두개이나 하나로 계산되는 반례가 생긴다. (그림 x가 3일 때)

(그림 출처 : https://sasca37.tistory.com/320)

#include <string>
#include <vector>
#include<bits/stdc++.h>

using namespace std;
/*
x^2 + y^2 = r^2  ->y^2 = r^2 - x^2  
y^2을 y로 만들고 내림한다. root 5의 경우 -> 2.xxx이니 2로 해야 원 내부에 rectangle 갯수(정수형)를 정확히 셀 수 있다.
바깥 원 rectangle 갯수 - 안 원 rectangle 갯수 + 4
사분표이기에 1사분포의 갯수만 구해서 * 4 하면 답.
*/
long long solution(int r1, int r2) {
    long long answer = 0;
    long long r1_recCnt = 0;
    long long r2_recCnt = 0;
    for(int x= 1; x < r1 ; ++x){
        long long y = floor(sqrt(r1*r1 - x*x));
        r1_recCnt += y;
    }
    for(int x = 1; x < r2; ++x){
        long long y = floor(sqrt(r2*r2 - x*x));
        r2_recCnt += y;
    }
    answer = ((r2_recCnt - r1_recCnt) + 2)  * 4;
    
    return answer;
}

 


기본 개념

배열의 stack over flow.

전역변수(전역 배열)는 에 Data영역에 저장.

지역변수(지역 배열), 매개변수는 stack 영역에 저장. 

 

stack과 heap은 한도가 존재.

#include<bits/stdc++.h>
using namespace std;
int arr3[1000001];
int main(void) {
	// 지역변수에서 배열의 사이즈 200,000 ~ 300,000 사이의 특정 값이상이면 stack over flow 발생
	// 전역변수의 경우 1백만까지도 발생하지 않음.
	// 동적 할당시 발생 x (arr1)
	// vector도 동적할당이니 발생 x
	int* arr1 = new int[1000001];
	vector<int> arr2;
	arr2.resize(1000001);
	
	int arr4[300000]; // stack overflow.
	delete arr1;
	
}

https://www.tcpschool.com/c/c_memory_structure

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

 

'PS > 프로그래머스' 카테고리의 다른 글

3진법 뒤집기  (0) 2023.07.29
[카카오 인턴] 키패드 누르기 [V]  (0) 2023.07.29
달리기 경주(O)  (0) 2023.07.28
연속된 부분 수열의 합(V)  (0) 2023.07.22
요격시스템 (-)  (0) 2023.07.21

+ Recent posts