함수 하나의 매개변수 목록과 그 함수를 부르는 호출들이 주어진다.
호출마다 인자가 어느 매개변수에 들어가는지 정해서, 매개변수가 받는 값을 출력하려고 한다.
첫 줄에 매개변수 수 p가, 다음 p줄에 매개변수가 선언 순서대로 한 줄에 하나씩 주어진다.
매개변수 줄은 "이름", "이름 정수", "이름 앞이름" 가운데 하나이다.
"이름"만 있으면 기본값이 없는 매개변수이고, "이름 정수"는 기본값이 그 정수인 매개변수이다.
"이름 앞이름"은 기본값이 '그 호출에서 앞이름 매개변수가 받은 값'인 매개변수이고, 앞이름은 더 앞줄에 선언된 매개변수의 이름이다.
다음 줄에 호출 수 q가, 다음 q줄에 호출이 한 줄에 하나씩 주어진다.
호출 줄은 call로 시작하고, 그 뒤에 인자 0개 이상이 빈칸 하나로 띄워 이어진다.
인자는 정수 하나인 자리 인자이거나, "이름=정수" 꼴의 이름 인자이다.
호출마다 인자를 왼쪽부터 하나씩 처리한다.
그 호출의 k번째 자리 인자는 k번째로 선언된 매개변수에 들어가고, 이름 인자는 그 이름의 매개변수에 들어간다.
인자를 처리하다가 아래 오류를 만나면 그 오류 한 줄만 출력하고, 그 호출의 남은 인자는 보지 않는다.
자리 인자가 이름 인자보다 뒤에 나왔으면 "error order"이다.
그렇지 않은데 자리 인자가 p개를 넘었으면 "error many"이다.
이름 인자의 이름이 매개변수에 없으면 "error unknown 이름"이다.
이름은 있지만 그 매개변수에 이 호출에서 이미 값이 들어갔으면 "error twice 이름"이다.
모든 인자를 오류 없이 처리했으면, 값이 들어가지 않은 매개변수를 선언 순서대로 기본값으로 채운다.
채우다가 기본값이 없는 매개변수를 만나면 "error missing 이름"을 출력하고 그 호출을 끝낸다.
오류가 없으면 매개변수 p개가 받은 값을 선언 순서대로 빈칸 하나로 띄워 한 줄에 출력하라.
호출은 서로 영향을 주지 않는다.
입력
1 ≤ p ≤ 8, 1 ≤ q ≤ 1,000. 이름은 영어 소문자 1 ~ 8글자이고, 매개변수 이름은 서로 다르며 call이 아니다. 정수는 모두 −1,000,000,000 이상 1,000,000,000 이하이고 음수는 앞에 -가 붙는다. 호출 하나의 인자는 12개 이하. 이름 인자에는 = 앞뒤로 빈칸이 없다
출력
호출마다 한 줄: 값 p개 또는 error order · error many · error unknown 이름 · error twice 이름 · error missing 이름
3 3 0 1
0 0 0 0
error twice w
error twice w
error order
error missing w
error many
error unknown dept
error twice depth
9 0 0 0
예시 2 · stdin
3
base 10
low base
high low
4
call
call 4
call low=0
call high=1 base=2
stdout
10 10 10
4 4 4
10 0 0
2 2 1
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
Python·C#에 있는 이름 붙인 인자와 기본값 규칙을 손으로 만들어 보는 문제예요. 실제 언어에서는 이래요. Python은 def box(w, h=None, depth=0, *, pad)를 box(3, pad=1)로 불러요. box(5, w=0)은 TypeError(got multiple values for argument 'w'), 없는 이름 dept=1도 TypeError이고, box(pad=2, 4)는 실행도 되기 전에 SyntaxError(positional argument follows keyword argument)예요. C#은 Box(3, pad: 1)로 쓰고, Box(5, w: 0)은 컴파일 오류 CS1744, Box(h: 2, 4)는 CS8323이에요(Box(w: 1, 2)처럼 제자리에 있는 이름 인자 뒤에는 자리 인자가 와도 돼요). JS·TS는 이름 인자가 없어서 객체 하나를 넘기고 function box({ w, h = w, depth = 0, pad })로 풀어 받아요. JS에서 box({ w: 1, w: 2 })는 오류 없이 뒤의 값이 이기고, 모르는 열쇠 dept는 조용히 버려져요. Java·C++·C·크레이콘에는 이름 인자가 없어요. C는 box((struct Box){ .w = 3, .pad = 1 })처럼 구조체로 흉내 내는데, 적지 않은 칸이 0이 돼서 '안 넣음'과 '0을 넣음'을 가를 수 없어요. 기본값도 달라요. C++ int h = 0은 뒤쪽 매개변수에만 달 수 있고 int h = w는 컴파일 오류예요. Python도 def g(w, h=w)는 NameError라서 h=None으로 받고 if h is None: h = w로 채워요. JS·TS는 function pos(w, h = w)가 되고 부를 때마다 계산해요. Java와 크레이콘은 기본값이 없어서 Java는 이름이 같은 함수를 여러 개 두고, 크레이콘은 값 개수가 다르면 멈춰요. 함정 하나: 넣은 값이 0일 수 있어요. '값이 들어갔나'를 Python if values[i]:처럼 값의 참거짓으로 물으면 0이 들어간 자리가 빈 자리로 보여서 call 0 w=5가 오류 없이 지나가요. Python is None, JS·TS === null, C# int?의 HasValue, Java Integer의 null, C++ std::optional의 has_value(), C는 따로 둔 bool 배열, 크레이콘은 != 빈값으로 물어요. Python h = h or w, JS h = h || w도 같은 함정이라 넣은 0이 기본값으로 바뀌어요. 함정 둘: 기본값 0도 기본값이에요. JS if (defaultValue[i])로 물으면 depth 0이 기본값 없는 매개변수가 돼요. 함정 셋: h w의 기본값은 그 호출에서 w가 받은 값이에요. 선언을 읽을 때 앞 매개변수의 기본값을 미리 베껴 두면 둘째 예시의 call 4가 4 10 10이 돼요. 앞 매개변수부터 차례로 채우면 돼요. 함정 넷: 오류는 인자를 왼쪽부터 보다가 처음 만난 것 하나예요. 종류별로 따로 훑으면 call pad=2 4 nope=1에서 order 대신 unknown이 나와요. missing도 선언 순서로 가장 앞의 것이라 call h=7은 pad가 아니라 w예요. 함정 다섯: 이름은 통째로 같아야 해요. C strncmp(names[i], name, strlen(name))처럼 앞부분만 비교하면 dept가 depth로 통해요.
Pythonmain.py · 64 줄
import sysdef bind(names, default_value, default_from, args): """인자를 매개변수에 맞춰 넣는다. (값 목록, "") 또는 (None, 오류)를 돌려준다.""" p = len(names) values = [None] * p # None = 아직 값이 들어가지 않음(0도 들어간 값이다) positional = 0 seen_named = False for arg in args: if "=" in arg: seen_named = True name, text = arg.split("=") if name not in names: return None, "unknown " + name i = names.index(name) if values[i] is not None: return None, "twice " + name values[i] = int(text) else: if seen_named: return None, "order" if positional == p: return None, "many" values[positional] = int(arg) positional += 1 for i in range(p): # 앞에서부터 채워야 앞 매개변수의 값을 기본값으로 쓸 수 있다 if values[i] is None: if default_from[i] >= 0: values[i] = values[default_from[i]] elif default_value[i] is not None: values[i] = default_value[i] else: return None, "missing " + names[i] return values, ""def main(): lines = sys.stdin.read().split("\n") p = int(lines[0]) names, default_value, default_from = [], [], [] for line in lines[1:1 + p]: parts = line.split() value, source = None, -1 if len(parts) == 2: if parts[1][0].isalpha(): source = names.index(parts[1]) else: value = int(parts[1]) names.append(parts[0]) default_value.append(value) default_from.append(source) q = int(lines[1 + p]) out = [] for line in lines[2 + p:2 + p + q]: values, error = bind(names, default_value, default_from, line.split()[1:]) if values is None: out.append("error " + error) else: out.append(" ".join(map(str, values))) print("\n".join(out))main()
JavaScriptmain.js · 56 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");// 인자를 매개변수에 맞춰 넣는다. 값 배열 또는 오류 문자열을 돌려준다.function bind(names, defaultValue, defaultFrom, args) { const p = names.length; const values = new Array(p).fill(null); // null = 아직 값이 들어가지 않음(0도 들어간 값이다) let positional = 0; let seenNamed = false; for (const arg of args) { const eq = arg.indexOf("="); if (eq >= 0) { seenNamed = true; const name = arg.slice(0, eq); const i = names.indexOf(name); if (i < 0) return "unknown " + name; if (values[i] !== null) return "twice " + name; values[i] = Number(arg.slice(eq + 1)); } else { if (seenNamed) return "order"; if (positional === p) return "many"; values[positional++] = Number(arg); } } for (let i = 0; i < p; i++) { if (values[i] !== null) continue; if (defaultFrom[i] >= 0) values[i] = values[defaultFrom[i]]; else if (defaultValue[i] !== null) values[i] = defaultValue[i]; else return "missing " + names[i]; } return values;}const p = Number(lines[0]);const names = [];const defaultValue = [];const defaultFrom = [];for (let i = 1; i <= p; i++) { const parts = lines[i].trim().split(" "); let value = null; let source = -1; if (parts.length === 2) { if (/^[a-z]/.test(parts[1])) source = names.indexOf(parts[1]); else value = Number(parts[1]); } names.push(parts[0]); defaultValue.push(value); defaultFrom.push(source);}const q = Number(lines[p + 1]);const out = [];for (let i = 0; i < q; i++) { const args = lines[p + 2 + i].trim().split(" ").slice(1); const result = bind(names, defaultValue, defaultFrom, args); out.push(typeof result === "string" ? "error " + result : result.join(" "));}console.log(out.join("\n"));
TypeScriptmain.ts · 62 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");// 인자를 매개변수에 맞춰 넣는다. 값 배열 또는 오류 문자열을 돌려준다.function bind(names: string[], defaultValue: (number | null)[], defaultFrom: number[], args: string[]): number[] | string { const p = names.length; const values: (number | null)[] = new Array<number | null>(p).fill(null); // null = 아직 값이 들어가지 않음 let positional = 0; let seenNamed = false; for (const arg of args) { const eq = arg.indexOf("="); if (eq >= 0) { seenNamed = true; const name = arg.slice(0, eq); const i = names.indexOf(name); if (i < 0) return "unknown " + name; if (values[i] !== null) return "twice " + name; values[i] = Number(arg.slice(eq + 1)); } else { if (seenNamed) return "order"; if (positional === p) return "many"; values[positional++] = Number(arg); } } const filled: number[] = []; for (let i = 0; i < p; i++) { let v: number | null = values[i]; if (v === null) { if (defaultFrom[i] >= 0) v = filled[defaultFrom[i]]; else v = defaultValue[i]; } if (v === null) return "missing " + names[i]; filled.push(v); } return filled;}const p: number = Number(lines[0]);const names: string[] = [];const defaultValue: (number | null)[] = [];const defaultFrom: number[] = [];for (let i = 1; i <= p; i++) { const parts: string[] = lines[i].trim().split(" "); let value: number | null = null; let source = -1; if (parts.length === 2) { if (/^[a-z]/.test(parts[1])) source = names.indexOf(parts[1]); else value = Number(parts[1]); } names.push(parts[0]); defaultValue.push(value); defaultFrom.push(source);}const q: number = Number(lines[p + 1]);const out: string[] = [];for (let i = 0; i < q; i++) { const args: string[] = lines[p + 2 + i].trim().split(" ").slice(1); const result = bind(names, defaultValue, defaultFrom, args); out.push(typeof result === "string" ? "error " + result : result.join(" "));}console.log(out.join("\n"));
JavaMain.java · 72 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;public class Main { static List<String> names = new ArrayList<>(); static List<Integer> defaultValue = new ArrayList<>(); // null = 기본값이 정수가 아님 static List<Integer> defaultFrom = new ArrayList<>(); // -1 = 앞 매개변수를 쓰지 않음 // 인자를 매개변수에 맞춰 넣는다. 오류가 없으면 values를 채우고 null을, 있으면 오류 문자열을 돌려준다. static String bind(String[] args, Integer[] values) { int p = names.size(); int positional = 0; boolean seenNamed = false; for (int a = 1; a < args.length; a++) { String arg = args[a]; int eq = arg.indexOf('='); if (eq >= 0) { seenNamed = true; String name = arg.substring(0, eq); int i = names.indexOf(name); if (i < 0) return "unknown " + name; if (values[i] != null) return "twice " + name; // null = 아직 값이 들어가지 않음 values[i] = Integer.parseInt(arg.substring(eq + 1)); } else { if (seenNamed) return "order"; if (positional == p) return "many"; values[positional++] = Integer.parseInt(arg); } } for (int i = 0; i < p; i++) { if (values[i] != null) continue; if (defaultFrom.get(i) >= 0) values[i] = values[defaultFrom.get(i)]; else if (defaultValue.get(i) != null) values[i] = defaultValue.get(i); else return "missing " + names.get(i); } return null; } public static void main(String[] argv) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); int p = Integer.parseInt(in.readLine().trim()); for (int i = 0; i < p; i++) { String[] parts = in.readLine().trim().split(" "); Integer value = null; int source = -1; if (parts.length == 2) { if (Character.isLetter(parts[1].charAt(0))) source = names.indexOf(parts[1]); else value = Integer.parseInt(parts[1]); } names.add(parts[0]); defaultValue.add(value); defaultFrom.add(source); } int q = Integer.parseInt(in.readLine().trim()); StringBuilder out = new StringBuilder(); for (int t = 0; t < q; t++) { String[] args = in.readLine().trim().split(" "); Integer[] values = new Integer[p]; String error = bind(args, values); if (error != null) { out.append("error ").append(error).append('\n'); } else { for (int i = 0; i < p; i++) out.append(i > 0 ? " " : "").append(values[i]); out.append('\n'); } } System.out.print(out); }}
C#Main.cs · 76 줄
using System;using System.Collections.Generic;using System.Text;class Program{ static List<string> names = new List<string>(); static List<int?> defaultValue = new List<int?>(); // null = 기본값이 정수가 아님 static List<int> defaultFrom = new List<int>(); // -1 = 앞 매개변수를 쓰지 않음 // 인자를 매개변수에 맞춰 넣는다. 오류가 없으면 values를 채우고 null을, 있으면 오류 문자열을 돌려준다. static string Bind(string[] args, int?[] values) { int p = names.Count; int positional = 0; bool seenNamed = false; for (int a = 1; a < args.Length; a++) { string arg = args[a]; int eq = arg.IndexOf('='); if (eq >= 0) { seenNamed = true; string name = arg.Substring(0, eq); int i = names.IndexOf(name); if (i < 0) return "unknown " + name; if (values[i].HasValue) return "twice " + name; // 0도 들어간 값이다 values[i] = int.Parse(arg.Substring(eq + 1)); } else { if (seenNamed) return "order"; if (positional == p) return "many"; values[positional++] = int.Parse(arg); } } for (int i = 0; i < p; i++) { if (values[i].HasValue) continue; if (defaultFrom[i] >= 0) values[i] = values[defaultFrom[i]]; else if (defaultValue[i].HasValue) values[i] = defaultValue[i]; else return "missing " + names[i]; } return null; } static void Main() { int p = int.Parse(Console.ReadLine().Trim()); for (int i = 0; i < p; i++) { string[] parts = Console.ReadLine().Trim().Split(' '); int? value = null; int source = -1; if (parts.Length == 2) { if (char.IsLetter(parts[1][0])) source = names.IndexOf(parts[1]); else value = int.Parse(parts[1]); } names.Add(parts[0]); defaultValue.Add(value); defaultFrom.Add(source); } int q = int.Parse(Console.ReadLine().Trim()); var sb = new StringBuilder(); for (int t = 0; t < q; t++) { string[] args = Console.ReadLine().Trim().Split(' '); var values = new int?[p]; string error = Bind(args, values); if (error != null) sb.Append("error ").Append(error).Append('\n'); else sb.Append(string.Join(" ", values)).Append('\n'); } Console.Write(sb); }}
C++main.cpp · 88 줄
#include <algorithm>#include <cctype>#include <iostream>#include <optional>#include <sstream>#include <string>#include <vector>using namespace std;struct Param { string name; optional<int> value; // 기본값이 정수일 때만 들어 있다 int from = -1; // 기본값이 앞 매개변수의 값이면 그 자리};// 인자를 매개변수에 맞춰 넣는다. 오류가 없으면 values를 채우고 빈 문자열을, 있으면 오류 문자열을 돌려준다.string bindArgs(const vector<Param>& params, const vector<string>& args, vector<int>& values) { int p = (int)params.size(); vector<optional<int>> slot(p); // 비어 있음 = 아직 값이 들어가지 않음(0도 들어간 값이다) int positional = 0; bool seenNamed = false; for (const string& arg : args) { size_t eq = arg.find('='); if (eq != string::npos) { seenNamed = true; string name = arg.substr(0, eq); auto it = find_if(params.begin(), params.end(), [&](const Param& x) { return x.name == name; }); if (it == params.end()) return "unknown " + name; int i = (int)(it - params.begin()); if (slot[i].has_value()) return "twice " + name; slot[i] = stoi(arg.substr(eq + 1)); } else { if (seenNamed) return "order"; if (positional == p) return "many"; slot[positional++] = stoi(arg); } } values.assign(p, 0); for (int i = 0; i < p; i++) { if (slot[i].has_value()) values[i] = *slot[i]; else if (params[i].from >= 0) values[i] = values[params[i].from]; else if (params[i].value.has_value()) values[i] = *params[i].value; else return "missing " + params[i].name; } return "";}int main() { string line; getline(cin, line); int p = stoi(line); vector<Param> params; for (int i = 0; i < p; i++) { getline(cin, line); istringstream in(line); Param x; string second; in >> x.name; if (in >> second) { if (isalpha((unsigned char)second[0])) { for (int j = 0; j < i; j++) if (params[j].name == second) x.from = j; } else { x.value = stoi(second); } } params.push_back(x); } getline(cin, line); int q = stoi(line); for (int t = 0; t < q; t++) { getline(cin, line); istringstream in(line); string word; in >> word; // call vector<string> args; while (in >> word) args.push_back(word); vector<int> values; string error = bindArgs(params, args, values); if (!error.empty()) { cout << "error " << error << "\n"; } else { for (int i = 0; i < p; i++) cout << (i ? " " : "") << values[i]; cout << "\n"; } } return 0;}
Cmain.c · 88 줄
#include <ctype.h>#include <stdbool.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#define MAXP 8static int p;static char names[MAXP][16];static bool has_default[MAXP]; /* 기본값이 정수인가 */static int default_value[MAXP];static int default_from[MAXP]; /* 앞 매개변수의 자리, 없으면 -1 */static int find_param(const char *name) { for (int i = 0; i < p; i++) if (strcmp(names[i], name) == 0) return i; return -1;}/* 인자를 매개변수에 맞춰 넣는다. 오류가 없으면 values를 채우고 true를, 오류가 있으면 error에 오류 문자열을 쓰고 false를 돌려준다. */static bool bind(char *args, int values[], char *error) { bool filled[MAXP] = {false}; /* 0도 들어간 값이라 값과 따로 적어 둔다 */ int positional = 0; bool seen_named = false; for (char *arg = strtok(args, " \r\n"); arg; arg = strtok(NULL, " \r\n")) { char *eq = strchr(arg, '='); if (eq) { seen_named = true; *eq = '\0'; int i = find_param(arg); if (i < 0) { sprintf(error, "unknown %s", arg); return false; } if (filled[i]) { sprintf(error, "twice %s", arg); return false; } values[i] = atoi(eq + 1); filled[i] = true; } else { if (seen_named) { strcpy(error, "order"); return false; } if (positional == p) { strcpy(error, "many"); return false; } values[positional] = atoi(arg); filled[positional] = true; positional++; } } for (int i = 0; i < p; i++) { if (filled[i]) continue; if (default_from[i] >= 0) values[i] = values[default_from[i]]; else if (has_default[i]) values[i] = default_value[i]; else { sprintf(error, "missing %s", names[i]); return false; } } return true;}int main(void) { static char line[1024]; if (!fgets(line, sizeof line, stdin)) return 0; p = atoi(line); for (int i = 0; i < p; i++) { char second[32] = ""; if (!fgets(line, sizeof line, stdin)) return 0; int got = sscanf(line, "%15s %31s", names[i], second); default_from[i] = -1; has_default[i] = false; if (got == 2) { if (isalpha((unsigned char)second[0])) { default_from[i] = find_param(second); } else { has_default[i] = true; default_value[i] = atoi(second); } } } if (!fgets(line, sizeof line, stdin)) return 0; int q = atoi(line); for (int t = 0; t < q; t++) { if (!fgets(line, sizeof line, stdin)) break; int values[MAXP]; char error[64]; /* 줄 맨 앞의 call은 건너뛴다 */ if (bind(line + 4, values, error)) { for (int i = 0; i < p; i++) printf(i ? " %d" : "%d", values[i]); printf("\n"); } else { printf("error %s\n", error); } } return 0;}
Craykonmain.cray · 92 줄
// 인자를 매개변수에 맞춰 넣는다. 출력할 한 줄(값들 또는 오류)을 돌려준다.맞추기(names, defaultValue, defaultFrom, args){ p = names.개수; values = 새목록(p, 빈값); // 빈값 = 아직 값이 들어가지 않음(0도 들어간 값이다) positional = 0; seenNamed = 거짓; 반복 (a = 1; a < args.개수; a++) { arg = args[a]; eq = arg.자리찾기("="); 만약 (eq >= 0) { seenNamed = 참; name = arg.부분문자열(0, eq); i = names.자리찾기(name); 만약 (i < 0) { 돌려주기 "error " + "unknown " + name; } 만약 (values[i] != 빈값) { 돌려주기 "error " + "twice " + name; } values[i] = arg.부분문자열(eq + 1).수로변환(); } 아니면 { 만약 (seenNamed) { 돌려주기 "error " + "order"; } 만약 (positional == p) { 돌려주기 "error " + "many"; } values[positional] = arg.수로변환(); positional = positional + 1; } } 반복 (i = 0; i < p; i++) { 만약 (values[i] == 빈값) { 만약 (defaultFrom[i] >= 0) { values[i] = values[defaultFrom[i]]; } 아니면 만약 (defaultValue[i] != 빈값) { values[i] = defaultValue[i]; } 아니면 { 돌려주기 "error " + "missing " + names[i]; } } } 돌려주기 values.잇기(" ");}p = 콘솔.줄읽기().수로변환();names = [];defaultValue = [];defaultFrom = [];반복 (i = 0; i < p; i++){ parts = 콘솔.줄읽기().공백제거().나누기(" "); value = 빈값; source = -1; 만약 (parts.개수 == 2) { 첫글자 = parts[1].부분문자열(0, 1); 만약 (첫글자 >= "a" && 첫글자 <= "z") { source = names.자리찾기(parts[1]); } 아니면 { value = parts[1].수로변환(); } } names.넣기(parts[0]); defaultValue.넣기(value); defaultFrom.넣기(source);}q = 콘솔.줄읽기().수로변환();반복 (t = 0; t < q; t++){ args = 콘솔.줄읽기().공백제거().나누기(" "); 콘솔.쓰기(맞추기(names, defaultValue, defaultFrom, args));}