숫자 현수막 기계는 입력으로 받은 글꼴로 숫자 문자열을 크게 찍는다.
글꼴에는 숫자 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 이하이다.
실행하면 이 줄들이 차례로 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 systokens = 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 = gwfor 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]][줄]); } 콘솔.쓰기(""); }}