{ }codelper
줄 안 바꾸고 출력P0404

숫자 글꼴로 찍는 현수막

숫자 현수막 기계는 입력으로 받은 글꼴로 숫자 문자열을 크게 찍는다. 글꼴에는 숫자 0부터 9까지 숫자마다 그림이 하나씩 있다. 그림 하나는 h줄이고, 각 줄은 #과 .로만 된 문자열이다. 한 그림의 줄들은 길이가 모두 같고, 이 길이를 그 숫자의 너비라 한다. 숫자마다 너비가 다를 수 있다. 찍을 숫자 문자열 s의 숫자들을 왼쪽부터 차례로 덩어리에 담는다. 한 덩어리 안에서는 그림을 왼쪽부터 나란히 놓고, 이웃한 두 그림 사이에 .으로만 된 열을 하나 끼운다. 덩어리의 너비는 그 안에 든 그림 너비의 합에 끼운 열의 수를 더한 값이다. s의 첫 숫자는 첫 덩어리에 담는다. 그다음 숫자부터는, 지금 덩어리에 담아도 덩어리의 너비가 W 이하이면 지금 덩어리에 담고, W를 넘게 되면 새 덩어리를 시작해 거기에 담는다. 덩어리는 만든 차례대로 출력한다. 덩어리 하나는 h줄로 출력하고, 그 k번째 줄은 덩어리 안 그림들의 k번째 줄을 왼쪽부터 . 하나씩 사이에 끼워 이어 붙인 것이다. 그래서 줄의 길이는 그 덩어리의 너비와 같고, 줄 맨 앞과 맨 끝에는 끼운 .이 오지 않는다. 이웃한 두 덩어리 사이에는 빈 줄을 하나 출력한다. 첫 덩어리 앞과 마지막 덩어리 뒤에는 빈 줄을 출력하지 않는다.

입력
첫 줄에 그림의 높이 h와 덩어리 너비의 상한 W가 빈칸 하나로 띄워 주어진다. 다음 10×h줄에 0의 그림, 1의 그림, …, 9의 그림이 차례로 h줄씩 주어진다. 마지막 줄에 숫자 문자열 s가 주어진다. 1 ≤ h ≤ 8이다. 그림의 너비는 1 이상 8 이하이고, 가장 넓은 그림의 너비 ≤ W ≤ 80이다.
그래서 그림 하나만 담은 덩어리는 늘 W를 넘지 않는다. s는 숫자 0~9로만 되어 있고, 길이는 1 이상 1,000 이하이다.
출력
덩어리마다 h줄.
이웃한 덩어리 사이에 빈 줄 하나
예시 1 · stdin
3 7
###
#.#
###
#
#
#
##.
.#.
.##
###
.##
###
#.#
###
..#
.##
.#.
##.
#..
###
###
##
.#
.#
###
###
###
###
###
..#
01230
stdout
###.#
#.#.#
###.#

##..###
.#...##
.##.###

###
#.#
###
main.py
입력(stdin)

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

$ 준비됐어요

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

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

이 문제는 한 줄을 여러 그림의 조각으로 이어 쓴 뒤에야 줄을 바꿔요.
그래서 바깥 반복은 줄(0 ~ h-1), 안쪽 반복은 덩어리 안의 그림이에요 — 그림 하나를 h줄 다 찍고 다음 그림으로 가면 숫자가 옆이 아니라 아래로 쌓여요.
줄을 바꾸지 않고 이어 쓰는 방법은 언어마다 달라요.
Python은 print(x, end="")(그냥 print(x)는 끝에 \n을 붙여요), JS·TS는 process.stdout.write(x)(console.log는 늘 줄을 바꿔요.
write를 조각마다 수만 번 부르면 느려서 풀이는 문자열에 이어 붙였다가 한 번에 써요), Java는 print와 println(풀이는 빠르게 쓰려고 PrintWriter에 모은 뒤 마지막에 flush()해요), C#은 Write와 WriteLine, C는 fputs·putchar·printf, C++은 std::cout << x(줄바꿈은 '\n'을 직접 넣어요), 크레이콘은 콘솔.이어쓰기(x)와 콘솔.쓰기(x)예요.
크레이콘에서 줄만 바꾸려면 콘솔.쓰기("")를 써요.
함정 하나: 줄을 바꾸는 출력 함수를 쓰는 것.
Python print(glyph[row])나, C에서 fputs 대신 puts를 쓰면(puts는 끝에 줄바꿈을 붙여요) 조각마다 줄이 바뀌어 예시의 첫 줄부터 ### 한 줄만 나와요.
함정 둘: 그림마다 뒤에 .을 붙이면 줄 끝에 .이 하나 남아요(예시 첫 줄이 ###.#.).
끝의 빈칸은 봐주는 채점기도 많지만 .은 보이는 글자라 그대로 틀려요.
첫 그림이 아닐 때만 앞에 .을 붙여요.
함정 셋: 덩어리 너비를 잘못 재는 것.
새 그림을 담을 때 늘어나는 너비는 그림 너비에 사이 열 1을 더한 값이에요.
사이 열을 빼고 재면 예시에서 0, 1, 2가 한 덩어리(실제 너비 9)에 담기고, ≤ W 대신 < W로 재면 너비가 딱 7인 두 번째 덩어리(2와 3)가 둘로 갈라져요.
함정 넷: 빈 줄은 덩어리 사이에만 넣어요.
빼먹으면 덩어리끼리 붙어 버리고, 덩어리마다 앞에 넣으면 첫 줄이 빈 줄이 돼요.
두 번째 덩어리부터 앞에 빈 줄을 하나 넣으면 돼요.

Pythonmain.py · 31 줄
import sys tokens = sys.stdin.read().split()h, w_max = int(tokens[0]), int(tokens[1])font = []for d in range(10):    font.append(tokens[2 + d * h: 2 + (d + 1) * h])s = tokens[2 + 10 * h] # 숫자들을 덩어리로 나눈다blocks = []width = 0for ch in s:    glyph = font[int(ch)]    gw = len(glyph[0])    if blocks and width + 1 + gw <= w_max:        blocks[-1].append(glyph)        width += 1 + gw    else:        blocks.append([glyph])        width = gw for b, block in enumerate(blocks):    if b > 0:        print()    for row in range(h):        for i, glyph in enumerate(block):            if i > 0:                print(".", end="")            print(glyph[row], end="")        print()
JavaScriptmain.js · 35 줄
const tokens = require("fs").readFileSync(0, "utf8").trim().split(/\s+/);const h = Number(tokens[0]);const maxWidth = Number(tokens[1]);const font = [];for (let d = 0; d < 10; d++) font.push(tokens.slice(2 + d * h, 2 + (d + 1) * h));const s = tokens[2 + 10 * h]; // 숫자들을 덩어리로 나눈다const blocks = [];let width = 0;for (const ch of s) {  const glyph = font[Number(ch)];  const gw = glyph[0].length;  if (blocks.length > 0 && width + 1 + gw <= maxWidth) {    blocks[blocks.length - 1].push(glyph);    width += 1 + gw;  } else {    blocks.push([glyph]);    width = gw;  }} // console.log는 늘 줄을 바꾼다. 조각을 문자열에 이어 붙였다가 process.stdout.write로 한 번에 쓴다let out = "";blocks.forEach((block, b) => {  if (b > 0) out += "\n";  for (let row = 0; row < h; row++) {    block.forEach((glyph, i) => {      if (i > 0) out += ".";      out += glyph[row];    });    out += "\n";  }});process.stdout.write(out);
TypeScriptmain.ts · 36 줄
import { readFileSync } from "node:fs";const tokens: string[] = readFileSync(0, "utf8").trim().split(/\s+/);const h: number = Number(tokens[0]);const maxWidth: number = Number(tokens[1]);const font: string[][] = [];for (let d = 0; d < 10; d++) font.push(tokens.slice(2 + d * h, 2 + (d + 1) * h));const s: string = tokens[2 + 10 * h]; // 숫자들을 덩어리로 나눈다const blocks: string[][][] = [];let width = 0;for (const ch of s) {  const glyph = font[Number(ch)];  const gw = glyph[0].length;  if (blocks.length > 0 && width + 1 + gw <= maxWidth) {    blocks[blocks.length - 1].push(glyph);    width += 1 + gw;  } else {    blocks.push([glyph]);    width = gw;  }} // console.log는 늘 줄을 바꾼다. 조각을 문자열에 이어 붙였다가 process.stdout.write로 한 번에 쓴다let out: string = "";blocks.forEach((block, b) => {  if (b > 0) out += "\n";  for (let row = 0; row < h; row++) {    block.forEach((glyph, i) => {      if (i > 0) out += ".";      out += glyph[row];    });    out += "\n";  }});process.stdout.write(out);
JavaMain.java · 48 줄
import java.io.*;import java.util.*; 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 h = Integer.parseInt(st.nextToken());        int maxWidth = Integer.parseInt(st.nextToken());        String[][] font = new String[10][h];        for (int d = 0; d < 10; d++)            for (int r = 0; r < h; r++)                font[d][r] = in.readLine().trim();        String s = in.readLine().trim();         // 숫자들을 덩어리로 나눈다        List<List<String[]>> blocks = new ArrayList<>();        int width = 0;        for (char ch : s.toCharArray()) {            String[] glyph = font[ch - '0'];            int gw = glyph[0].length();            if (!blocks.isEmpty() && width + 1 + gw <= maxWidth) {                blocks.get(blocks.size() - 1).add(glyph);                width += 1 + gw;            } else {                List<String[]> block = new ArrayList<>();                block.add(glyph);                blocks.add(block);                width = gw;            }        }         // print는 줄을 바꾸지 않고, println은 바꾼다        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));        for (int b = 0; b < blocks.size(); b++) {            if (b > 0) out.println();            List<String[]> block = blocks.get(b);            for (int row = 0; row < h; row++) {                for (int i = 0; i < block.size(); i++) {                    if (i > 0) out.print('.');                    out.print(block.get(i)[row]);                }                out.println();            }        }        out.flush();    }}
C#Main.cs · 56 줄
using System;using System.Collections.Generic;using System.IO; class Program{    static void Main()    {        string[] first = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int h = int.Parse(first[0]);        int maxWidth = int.Parse(first[1]);        var font = new string[10][];        for (int d = 0; d < 10; d++)        {            font[d] = new string[h];            for (int r = 0; r < h; r++) font[d][r] = Console.ReadLine().Trim();        }        string s = Console.ReadLine().Trim();         // 숫자들을 덩어리로 나눈다        var blocks = new List<List<string[]>>();        int width = 0;        foreach (char ch in s)        {            string[] glyph = font[ch - '0'];            int gw = glyph[0].Length;            if (blocks.Count > 0 && width + 1 + gw <= maxWidth)            {                blocks[^1].Add(glyph);                width += 1 + gw;            }            else            {                blocks.Add(new List<string[]> { glyph });                width = gw;            }        }         // Write는 줄을 바꾸지 않고, WriteLine은 바꾼다        var output = new StreamWriter(Console.OpenStandardOutput());        for (int b = 0; b < blocks.Count; b++)        {            if (b > 0) output.WriteLine();            for (int row = 0; row < h; row++)            {                for (int i = 0; i < blocks[b].Count; i++)                {                    if (i > 0) output.Write('.');                    output.Write(blocks[b][i][row]);                }                output.WriteLine();            }        }        output.Flush();    }}
C++main.cpp · 42 줄
#include <iostream>#include <string>#include <vector>using namespace std; int main() {    int h, maxWidth;    cin >> h >> maxWidth;    vector<vector<string>> font(10, vector<string>(h));    for (int d = 0; d < 10; d++)        for (int r = 0; r < h; r++) cin >> font[d][r];    string s;    cin >> s;     // 숫자들을 덩어리로 나눈다    vector<vector<int>> blocks;    int width = 0;    for (char ch : s) {        int digit = ch - '0';        int gw = (int)font[digit][0].size();        if (!blocks.empty() && width + 1 + gw <= maxWidth) {            blocks.back().push_back(digit);            width += 1 + gw;        } else {            blocks.push_back({digit});            width = gw;        }    }     // cout << 는 줄을 바꾸지 않는다. 줄바꿈은 '\n'으로 직접 넣는다    for (size_t b = 0; b < blocks.size(); b++) {        if (b > 0) cout << '\n';        for (int row = 0; row < h; row++) {            for (size_t i = 0; i < blocks[b].size(); i++) {                if (i > 0) cout << '.';                cout << font[blocks[b][i]][row];            }            cout << '\n';        }    }    return 0;}
Cmain.c · 42 줄
#include <stdio.h>#include <string.h> char font[10][8][9]; /* 숫자 10개 × 줄 8개 × (글자 8개 + '\0') */char s[1001];int blockStart[1001]; /* 덩어리마다 첫 숫자의 자리 */ int main(void) {    int h, maxWidth;    scanf("%d %d", &h, &maxWidth);    for (int d = 0; d < 10; d++)        for (int r = 0; r < h; r++)            scanf("%8s", font[d][r]);    scanf("%1000s", s);    int n = (int)strlen(s);     /* 숫자들을 덩어리로 나눈다 */    int blocks = 0, width = 0;    for (int i = 0; i < n; i++) {        int gw = (int)strlen(font[s[i] - '0'][0]);        if (blocks > 0 && width + 1 + gw <= maxWidth) {            width += 1 + gw;        } else {            blockStart[blocks++] = i;            width = gw;        }    }    blockStart[blocks] = n;     /* puts는 끝에 줄바꿈을 붙이므로 fputs·putchar로 이어 쓴다 */    for (int b = 0; b < blocks; b++) {        if (b > 0) putchar('\n');        for (int row = 0; row < h; row++) {            for (int i = blockStart[b]; i < blockStart[b + 1]; i++) {                if (i > blockStart[b]) putchar('.');                fputs(font[s[i] - '0'][row], stdout);            }            putchar('\n');        }    }    return 0;}
Craykonmain.cray · 55 줄
첫줄 = 콘솔.수들읽기();h = 첫줄[0];최대너비 = 첫줄[1];글꼴 = [];반복 (d = 0; d < 10; d++){    그림 = [];    반복 (r = 0; r < h; r++)    {        그림.넣기(콘솔.줄읽기().공백제거());    }    글꼴.넣기(그림);}s = 콘솔.줄읽기().공백제거(); // 숫자들을 덩어리로 나눈다덩어리들 = [];너비 = 0;각각 (c 에서 s){    숫자 = c.수로변환();    그림너비 = 글꼴[숫자][0].길이;    만약 (덩어리들.개수 > 0 && 너비 + 1 + 그림너비 <= 최대너비)    {        덩어리들[덩어리들.개수 - 1].넣기(숫자);        너비 += 1 + 그림너비;    }    아니면    {        덩어리들.넣기([숫자]);        너비 = 그림너비;    }} // 콘솔.쓰기는 줄을 바꾸고, 콘솔.이어쓰기는 바꾸지 않는다반복 (b = 0; b < 덩어리들.개수; b++){    만약 (b > 0)    {        콘솔.쓰기("");    }    덩어리 = 덩어리들[b];    반복 (줄 = 0; 줄 < h; 줄++)    {        반복 (i = 0; i < 덩어리.개수; i++)        {            만약 (i > 0)            {                콘솔.이어쓰기(".");            }            콘솔.이어쓰기(글꼴[덩어리[i]][줄]);        }        콘솔.쓰기("");    }}