[C++/백준] 2477번 참외밭

2023. 2. 16. 14:55C++

https://www.acmicpc.net/problem/2477

 

2477번: 참외밭

첫 번째 줄에 1m2의 넓이에 자라는 참외의 개수를 나타내는 양의 정수 K (1 ≤ K ≤ 20)가 주어진다. 참외밭을 나타내는 육각형의 임의의 한 꼭짓점에서 출발하여 반시계방향으로 둘레를 돌면서 지

www.acmicpc.net

문제

시골에 있는 태양이의 삼촌 댁에는 커다란 참외밭이 있다. 문득 태양이는 이 밭에서 자라는 참외가 도대체 몇 개나 되는지 궁금해졌다. 어떻게 알아낼 수 있는지 골똘히 생각하다가 드디어 좋은 아이디어가 떠올랐다. 유레카! 1m2의 넓이에 자라는 참외 개수를 헤아린 다음, 참외밭의 넓이를 구하면 비례식을 이용하여 참외의 총개수를 구할 수 있다.

1m2의 넓이에 자라는 참외의 개수는 헤아렸고, 이제 참외밭의 넓이만 구하면 된다. 참외밭은 ㄱ-자 모양이거나 ㄱ-자를 90도, 180도, 270도 회전한 모양(┏, ┗, ┛ 모양)의 육각형이다. 다행히도 밭의 경계(육각형의 변)는 모두 동서 방향이거나 남북 방향이었다. 밭의 한 모퉁이에서 출발하여 밭의 둘레를 돌면서 밭경계 길이를 모두 측정하였다.

예를 들어 참외밭이 위 그림과 같은 모양이라고 하자. 그림에서 오른쪽은 동쪽, 왼쪽은 서쪽, 아래쪽은 남쪽, 위쪽은 북쪽이다. 이 그림의 왼쪽위 꼭짓점에서 출발하여, 반시계방향으로 남쪽으로 30m, 동쪽으로 60m, 남쪽으로 20m, 동쪽으로 100m, 북쪽으로 50m, 서쪽으로 160m 이동하면 다시 출발점으로 되돌아가게 된다.

위 그림의 참외밭  면적은 6800m2이다. 만약 1m2의 넓이에 자라는 참외의 개수가 7이라면, 이 밭에서 자라는 참외의 개수는 47600으로 계산된다.

1m2의 넓이에 자라는 참외의 개수와, 참외밭을 이루는 육각형의 임의의 한 꼭짓점에서 출발하여 반시계방향으로 둘레를 돌면서 지나는 변의 방향과 길이가 순서대로 주어진다. 이 참외밭에서 자라는 참외의 수를 구하는 프로그램을 작성하시오.

입력

첫 번째 줄에 1m2의 넓이에 자라는 참외의 개수를 나타내는 양의 정수 K (1 ≤ K ≤ 20)가 주어진다. 참외밭을 나타내는 육각형의 임의의 한 꼭짓점에서 출발하여 반시계방향으로 둘레를 돌면서 지나는 변의 방향과 길이 (1 이상 500 이하의 정수) 가 둘째 줄부터 일곱 번째 줄까지 한 줄에 하나씩 순서대로 주어진다. 변의 방향에서 동쪽은 1, 서쪽은 2, 남쪽은 3, 북쪽은 4로 나타낸다.

출력

첫째 줄에 입력으로 주어진 밭에서 자라는 참외의 수를 출력한다.


문제를 어떤방식으로 풀지는 해결했지만 구현 부분에서 막혔다. 방향과 길이가 6줄에 걸쳐서 입력되는데 모든 경우에서 겹치는 방향이 두 개가 생긴다는 것입니다.

ex) ㄱ자는 4-2-3-1-3-1

      ㄴ자는 4-2-4-2-3-1

위 그림에서 육각형의 넓이를 구하기 위해선 가장 큰 사각형 위에 예시에서는 (가로 : 160, 세로 :50) 넓이에서 비어있는 사각형 (가로 : 60, 세로 :20)의 넓이를 빼주면 우리가 원하는 도형의 넓이가 나오게 됩니다.

3-1-3-1, 4-2-4-2 과 같이  방향이 겹치는 곳에서 중간에있는 1-3과 2-4가 비어있는 사각형의 가로 세로가 되기때문에 저 두곳의 길이만 빼서 계산을 해주면 됩니다.

여기서 제가 구현을 못했던 부분은 항상 3-1-3-1, 4-2-4-2와 같은 패턴이 나오지 않는다는 것입니다. 출발점하는 꼭지점이 케이스에 따라 바뀌기 떄문에 같은 도형이라도 주어지는 입력은 다르게 나타난다는 것입니다.

 

ex) 4-2-3-1-3-1 과 1-4-2-3-1-3 은 같은 모양의 도형입니다 출발점만 다릅니다.

 

처음에 구현 할때는 겹치는 부분의 인덱스만 뽑아서 새로운 배열에 집어넣고 가운데 두 곳만 뽑아서 계산하는 방식으로 했습니다. 이 방식은 위와 같은 케이스가 나올때 방법이 먹히지 않는다는 것입니다.

 

여기서 풀이를 참고하였는데 원형배열처럼 사용하는 방식이었습니다. 겹치는 인덱스를 카운트해놨다가. 안겹치는 방향은 그대로 큰 도형의 가로 세로로 계산하고, 겹치는 방향은 처음 겹치는 방향을 만났을때 두 칸뒤가 본인과 같은 방향인지 체크하고 같은 방향이라면 본인의 다음 방향을 곱해주어 비어있는 사각형의 넓이를 구해줍니다.

for(int i=0;i<=6;i++)
    {
        if(cnt[arr[i][0]]==1)
        {
            big_sq*=arr[i][1];
            continue;
        }
        int n = (i+1)%6;
        int nn = (i+2)%6; //내 다음과 다다음이 뭔지 체크
        
        if(arr[i][0] == arr[nn][0]) //다다음 과 같다면
            sm_sq *= arr[n][1]; //내 다음을 곱함
    }

 이런 방식의 케이스가 존재하는 문제를 만나면 선형 배열이 아닌 원형 배열처럼 탐색하도록 하는게 핵심이란 것을 배웠습니다.

전체소스코드

#include <iostream>
#include <vector>
using namespace std;

int n;
int arr[8][4];
int cnt[5];
int main()
{
    cin>>n;
    int big_sq = 1;
    int sm_sq = 1;
    for(int i=0;i<6;i++)
    {
        cin>>arr[i][0]>>arr[i][1];
        cnt[arr[i][0]]++;
    }
    
    for(int i=0;i<=6;i++)
    {
        if(cnt[arr[i][0]]==1)
        {
            big_sq*=arr[i][1];
            continue;
        }
        int n = (i+1)%6;
        int nn = (i+2)%6; //내 다음과 다다음이 뭔지 체크
        
        if(arr[i][0] == arr[nn][0]) //다다음 과 같다면
            sm_sq *= arr[n][1]; //내 다음을 곱함
    }
    
    cout<<(big_sq-sm_sq)*n<<endl;
    return 0;
}