Outdated/Algorithm Solution

[BOJ] 1022번 소용돌이 예쁘게 출력하기

해달 2020. 1. 16. 08:00

문제

크기가 무한인 정사각형 모눈종이가 있다. 모눈종이의 각 정사각형은 행과 열의 쌍으로 표현할 수 있다. 이 모눈종이 전체를 양의 정수의 소용돌이 모양으로 채울 것이다. 일단 숫자 1을 0행 0열에 쓴다. 그리고 나서 0행 1열에 숫자 2를 쓴다. 거기서 부터 소용돌이는 반시계 방향으로 시작된다. 다음 숫자는 다음과 같이 채우면 된다.


   -3 -2 -1  0 1 2 3

    --------------------

-3 |37 36 35 34 33 32 31

-2 |38 17 16 15 14 13 30

-1 |39 18  5 4 3 12 29

 0 |40 19  6 1 2 11 28

 1 |41 20  7 8 9 10 27

 2 |42 21 22 23 24 25 26

 3 |43 44 45 46 47 48 49

이 문제는 위와 같이 채운 것을 예쁘게 출력하면 된다. r1, c1, r2, c2가 입력으로 주어진다. r1, c1은 가장 왼쪽 위 칸이고, r2, c2는 가장 오른쪽 아래 칸이다.

예쁘게 출력한다는 것은 다음과 같이 출력하는 것이다.

  1. 출력은 r1행부터 r2행까지 차례대로 출력한다.

  2. 각 원소는 공백으로 구분한다.

  3. 모든 행은 같은 길이를 가져야 한다.

  4. 공백의 길이는 최소로 해야 한다.

  5. 모든 숫자의 길이(앞에 붙는 공백을 포함)는 같아야 한다.

  6. 만약 수의 길이가 가장 길이가 긴 수보다 작다면, 왼쪽에서부터 공백을 삽입해 길이를 맞춘다.


입력

첫째 줄에 r1, c1, r2, c2가 주어진다. 모두 절댓값이 5000보다 작거나 같은 정수이고, r2-r1은 0보다 크거나 같고, 49보다 작거나 같으며, c2-c1은 0보다 크거나 같고, 4보다 작거나 같다.


출력

r2-r1+1개의 줄에 소용돌이를 예쁘게 출력한다.


코드

  • C++ 17


#include <iostream>

#include <iomanip>

#include <algorithm>

 

using namespace std;

 

int R1, C1, R2, C2;

 

// (r, c)의 값을 구한다.

int GetValue(int r, int c)

{

    // 이 문제를 풀기 위해서는 소용돌이의 규칙을 알아야 한다.

    // 소용돌이는 (n, n)이 마지막이며, 여기서 1씩 줄어든다.

    // 조금 계산해보면 공식이 (2n + 1)^2 임을 알 수 있다.

    // 마지막 값을 구한 후 각 꼭짓점을 중심으로 값을 계산해낼 수 있다.

    

 

 

    // r과 c의 절대값 중 최대값을 구한다.

    int n = max(abs(r), abs(c));

 

    // 해당 소용돌이의 마지막 값을 계산한다.

    int last = (2 * n + 1) * (2 * n + 1);

 

    // r과 c의 값에 따라 값을 계산한다.

    // 아랫변

    if (r == n)

        return last - (n - c);

    // 왼쪽 변

    else if (c == -n)

        return last - (2 * n) - (n - r);

    // 윗변

    else if (r == -n)

        return last - (4 * n) - (n + c);

    // 오른쪽 변

    else

        return last - (6 * n) - (n + r);

}

 

// 자릿수를 계산한다.

int GetNumberOfDigit(int value)

{

    return (value ? GetNumberOfDigit(value / 10) + 1 : 0);

}

 

int main()

{

    ios::sync_with_stdio(false);

    cout.tie(nullptr);

    cout.tie(nullptr);

 

    // 입력 받는다.

    cin >> R1 >> C1 >> R2 >> C2;

 

    // 자릿수를 계산한다.

    int w = 0;

    for (int r = R1; r <= R2; ++r)

    {

        for (int c = C1; c <= C2; ++c)

            w = max(w, GetNumberOfDigit(GetValue(r, c)));

    }

 

    // 출력한다.

    for (int r = R1; r <= R2; ++r)

    {

        for (int c = C1; c <= C2; ++c)

            cout << setw(w) << GetValue(r, c) << ' ';

        cout << '\n';

    }

}


  • C# 6.0


using System;

using System.Collections.Generic;

using System.Text;

 

namespace ForAlgoCsharp

{

    class Program

    {

        static int R1, C1, R2, C2;

 

        static int GetValue(int r, int c)

        {

            int n = Math.Max(Math.Abs(r), Math.Abs(c));

 

            int last = n * 2 + 1;

            last *= last;

 

            if (r == n)

                return last - (n - c);

            else if (c == -n)

                return last - (2 * n) - (n - r);

            else if (r == -n)

                return last - (4 * n) - (n + c);

            else

                return last - (6 * n) - (n + r);

        }

 

        static int GetNumberOfDigit(int value) =>

            (value != 0 ? GetNumberOfDigit(value / 10) + 1 : 0);

 

        static void Main(string[] args)

        {

            string[] inputs = Console.ReadLine().Split();

            R1 = Convert.ToInt32(inputs[0]);

            C1 = Convert.ToInt32(inputs[1]);

            R2 = Convert.ToInt32(inputs[2]);

            C2 = Convert.ToInt32(inputs[3]);

 

            int w = 0;

            for (int r = R1; r <= R2; ++r)

            {

                for (int c = C1; c <= C2; ++c)

                    w = Math.Max(w, GetNumberOfDigit(GetValue(r, c)));

            }

 

            StringBuilder sb = new StringBuilder();

            for (int r = R1; r <= R2; ++r)

            {

                for (int c = C1; c <= C2; ++c)

                    sb.Append(GetValue(r, c).ToString().PadLeft(w)).Append(' ');

                sb.AppendLine();

            }

            Console.Write(sb);

        }

    }

}


  • Python 3


from sys import stdin, stdout

 

def getValue(r, c):

    n = max(abs(r), abs(c))

    last = 2 * n + 1

    last *= last

 

    if (r == n):

        return last - (n - c)

    elif (c == -n):

        return last - 2 * n - (n - r)

    elif (r == -n):

        return last - 4 * n - (n + c)

    else:

        return last - 6 * n - (n + r)

 

def getDigit(value):

    return (getDigit(value // 10) + 1 if value != 0 else 0)

 

R1, C1, R2, C2 = tuple(map(int, input().split()))

 

w = 0

for r in range(R1, R2 + 1):

    for c in range(C1, C2 + 1):

        w = max(w, getDigit(getValue(r, c)))

 

output = []

for r in range(R1, R2 + 1):

    for c in range(C1, C2 + 1):

        output.append(f'{getValue(r, c): >{w}} ')

    output.append('\n')

stdout.write(''.join(output))


복기

C++의 출력 조정자는 여기와 같다. C#의 출력 형식은 PadLeft(), PadRight() 등을 줄 수 있다. python은 여기를 참고할 수 있다.