{ }codelper
범위 반복건너뛰며 반복2차원 목록P0335

조각보의 사선 줄을 몇 번째마다 뽑기

세로 R줄, 가로 C칸인 조각보의 칸마다 영어 소문자 하나가 적혀 있다. 줄은 위에서부터 1번, 칸은 왼쪽에서부터 1번이다. (줄 번호 + 칸 번호 − 1)이 d인 칸들을 d번 사선이라고 한다.
사선은 1번부터 R + C − 1번까지 있다. 사선 하나를 읽을 때는 그 사선의 가장 아래 줄에 있는 칸부터 위 줄로 올라가며(왼쪽 아래에서 오른쪽 위로) 문자를 이어 붙인다. a번 사선부터 s개씩 건너뛰며 a, a + s, a + 2 × s, … 가운데 b 이하인 번호의 사선을 차례로 읽는다. 첫 줄에 R과 C가 빈칸 하나로 띄워 주어진다. 다음 R줄에 줄마다 길이가 C인 문자열이 주어진다. 마지막 줄에 a, b, s가 빈칸 하나로 띄워 주어진다. 읽은 사선마다 한 줄에 이어 붙인 문자열을 번호가 작은 사선부터 출력하라. 사선에 없는 칸은 보지 말고, 반복문의 시작과 끝을 계산해서 그 사선의 칸만 돌아 보자.

입력
1 ≤ R ≤ 100.
1 ≤ C ≤ 100.
1 ≤ a ≤ b ≤ R + C − 1.
1 ≤ s ≤ R + C − 1.
문자는 모두 영어 소문자
출력
읽은 사선마다 한 줄씩
예시 1 · stdin
3 4
abcd
efgh
ijkl
2 6 2
stdout
eb
jgd
l
예시 2 · stdin
4 2
ab
cd
ef
gh
1 5 1
stdout
a
cb
ed
gf
h
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

건너뛰며 세는 반복은 Python for d in range(a, b + 1, s), 나머지 언어는 for (d = a; d <= b; d += s)(크레이콘 반복 (d = a; d <= b; d += s))로 써요.
한 사선 안에서는 0부터 센 줄 r과 칸 c가 r + c = d − 1이라서, 줄을 min(d - 1, R - 1)에서 max(0, d - C)까지 거꾸로 세고 칸은 d - 1 - r로 구해요.
거꾸로 세기는 Python range(low, high - 1, -1), 나머지는 for (r = low; r >= high; r--)예요.
작은 쪽·큰 쪽은 Python min/max, JS·TS·Java Math.min/Math.max, C# Math.Min/Math.Max, C++ std::min/std::max, 크레이콘 수학.작은수/수학.큰수이고 C는 a < b ? a : b로 써요.
함정 ① Python range는 끝 값을 넣지 않아요.
range(a, b, s)로 쓰면 (b − a)가 s의 배수일 때 b번 사선이 빠져요(첫 예시에서 마지막 줄 l이 안 나와요).
거꾸로 셀 때도 같아서 range(low, high, -1)은 가장 위 칸을 빠뜨려요(첫 예시가 e, jg와 값이 없는 줄이 돼요).
② 가장 위 줄은 가로 칸 수 C로 정해져요.
max(0, d - R)처럼 R을 쓰면 정사각형에서만 맞고, 가로로 긴 조각보에서는 문자가 빠지고 세로로 긴 조각보에서는 없는 칸을 읽어요.
③ 범위를 계산하지 않고 모든 줄을 돌며 c < C만 확인하면 c가 음수인 칸이 남아요.
Python은 grid[r][-1]을 오류 없이 그 줄의 마지막 문자로 읽어서 첫 예시의 첫 줄이 leb가 돼요.
JS·TS는 undefined를 돌려줘 "undefined"가 붙고, Java·C#은 예외로 멈추고, 크레이콘도 '문자열에는 0~3번만 있어요'라며 멈추고, C·C++는 배열 밖을 읽어요.
④ 방향을 반대로(위 줄에서 아래 줄로) 돌면 문자열이 뒤집혀요.
⑤ d += s 대신 d++로 쓰면 건너뛰지 않고 모든 사선이 나와요.

Pythonmain.py · 20 줄
import sys  def main():    lines = sys.stdin.read().split()    R, C = int(lines[0]), int(lines[1])    grid = lines[2:2 + R]    a, b, s = (int(x) for x in lines[2 + R:5 + R])     out = []    for d in range(a, b + 1, s):  # range는 끝을 넣지 않으므로 b + 1까지        # d번 사선의 칸은 (0부터 센) 줄 r + 칸 c = d - 1을 만족한다        low = min(d - 1, R - 1)  # 가장 아래 줄        high = max(0, d - C)  # 가장 위 줄        # 거꾸로 셀 때도 끝은 들어가지 않는다: high - 1까지        out.append("".join(grid[r][d - 1 - r] for r in range(low, high - 1, -1)))    print("\n".join(out))  main()
JavaScriptmain.js · 18 줄
const lines = require("fs").readFileSync(0, "utf8").split(/\s+/).filter((s) => s !== "");const R = Number(lines[0]);const C = Number(lines[1]);const grid = lines.slice(2, 2 + R);const [a, b, s] = lines.slice(2 + R, 5 + R).map(Number); const out = [];for (let d = a; d <= b; d += s) {  // d번 사선의 칸은 (0부터 센) 줄 r + 칸 c = d - 1을 만족한다  const low = Math.min(d - 1, R - 1); // 가장 아래 줄  const high = Math.max(0, d - C); // 가장 위 줄  let line = "";  for (let r = low; r >= high; r--) {    line += grid[r][d - 1 - r];  }  out.push(line);}console.log(out.join("\n"));
TypeScriptmain.ts · 22 줄
import { readFileSync } from "node:fs"; const lines: string[] = readFileSync(0, "utf8").split(/\s+/).filter((s) => s !== "");const R: number = Number(lines[0]);const C: number = Number(lines[1]);const grid: string[] = lines.slice(2, 2 + R);const a: number = Number(lines[2 + R]);const b: number = Number(lines[3 + R]);const s: number = Number(lines[4 + R]); const out: string[] = [];for (let d = a; d <= b; d += s) {  // d번 사선의 칸은 (0부터 센) 줄 r + 칸 c = d - 1을 만족한다  const low: number = Math.min(d - 1, R - 1); // 가장 아래 줄  const high: number = Math.max(0, d - C); // 가장 위 줄  let line = "";  for (let r = low; r >= high; r--) {    line += grid[r][d - 1 - r];  }  out.push(line);}console.log(out.join("\n"));
JavaMain.java · 30 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringTokenizer; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        StringTokenizer st = new StringTokenizer(in.readLine());        int R = Integer.parseInt(st.nextToken()), C = Integer.parseInt(st.nextToken());        String[] grid = new String[R];        for (int r = 0; r < R; r++) {            grid[r] = in.readLine().trim();        }        st = new StringTokenizer(in.readLine());        int a = Integer.parseInt(st.nextToken()), b = Integer.parseInt(st.nextToken()), s = Integer.parseInt(st.nextToken());         StringBuilder out = new StringBuilder();        for (int d = a; d <= b; d += s) {            // d번 사선의 칸은 (0부터 센) 줄 r + 칸 c = d - 1을 만족한다            int low = Math.min(d - 1, R - 1); // 가장 아래 줄            int high = Math.max(0, d - C); // 가장 위 줄            for (int r = low; r >= high; r--) {                out.append(grid[r].charAt(d - 1 - r));            }            out.append('\n');        }        System.out.print(out);    }}
C#Main.cs · 32 줄
using System;using System.Text; class Program{    static void Main()    {        string[] head = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int R = int.Parse(head[0]), C = int.Parse(head[1]);        string[] grid = new string[R];        for (int r = 0; r < R; r++)        {            grid[r] = Console.ReadLine().Trim();        }        string[] tail = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int a = int.Parse(tail[0]), b = int.Parse(tail[1]), s = int.Parse(tail[2]);         var sb = new StringBuilder();        for (int d = a; d <= b; d += s)        {            // d번 사선의 칸은 (0부터 센) 줄 r + 칸 c = d - 1을 만족한다            int low = Math.Min(d - 1, R - 1); // 가장 아래 줄            int high = Math.Max(0, d - C); // 가장 위 줄            for (int r = low; r >= high; r--)            {                sb.Append(grid[r][d - 1 - r]);            }            sb.Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 26 줄
#include <algorithm>#include <iostream>#include <string>#include <vector> int main() {    std::ios::sync_with_stdio(false);    std::cin.tie(nullptr);    int R, C;    std::cin >> R >> C;    std::vector<std::string> grid(R);    for (auto& row : grid) std::cin >> row;    int a, b, s;    std::cin >> a >> b >> s;     for (int d = a; d <= b; d += s) {        // d번 사선의 칸은 (0부터 센) 줄 r + 칸 c = d - 1을 만족한다        int low = std::min(d - 1, R - 1); // 가장 아래 줄        int high = std::max(0, d - C);    // 가장 위 줄        std::string line;        for (int r = low; r >= high; r--) {            line += grid[r][d - 1 - r];        }        std::cout << line << '\n';    }}
Cmain.c · 23 줄
#include <stdio.h> static char grid[100][101]; int main(void) {    int R, C, a, b, s;    scanf("%d %d", &R, &C);    for (int r = 0; r < R; r++) {        scanf("%100s", grid[r]);    }    scanf("%d %d %d", &a, &b, &s);     for (int d = a; d <= b; d += s) {        /* d번 사선의 칸은 (0부터 센) 줄 r + 칸 c = d - 1을 만족한다 */        int low = d - 1 < R - 1 ? d - 1 : R - 1; /* 가장 아래 줄 */        int high = d - C > 0 ? d - C : 0;        /* 가장 위 줄 */        for (int r = low; r >= high; r--) {            putchar(grid[r][d - 1 - r]);        }        putchar('\n');    }    return 0;}
Craykonmain.cray · 25 줄
head = 콘솔.수들읽기();R = head[0];C = head[1];grid = [];반복 (r = 0; r < R; r++){    grid.넣기(콘솔.줄읽기().공백제거());}tail = 콘솔.수들읽기();a = tail[0];b = tail[1];s = tail[2]; 반복 (d = a; d <= b; d += s){    // d번 사선의 칸은 (0부터 센) 줄 r + 칸 c = d - 1을 만족한다    low = 수학.작은수(d - 1, R - 1);    high = 수학.큰수(0, d - C);    line = "";    반복 (r = low; r >= high; r--)    {        line += grid[r][d - 1 - r];    }    콘솔.쓰기(line);}