{ }codelper
자료 목록P0319

주말농장 밭 기록부

주말농장에 1번부터 n번까지 밭 n개가 있다. 밭마다 기록이 하나씩 있고, 기록에는 작물 이름, 물 준 횟수, 거둔 양이 적힌다. 처음에는 모든 밭이 작물 이름 -, 물 준 횟수 0, 거둔 양 0이다. 명령은 세 가지이다. plant k 이름은 k번 밭의 작물 이름을 그 이름으로 바꾸고 물 준 횟수를 0으로 되돌린다(거둔 양은 그대로 둔다). water k는 k번 밭의 물 준 횟수를 1 늘린다. pick k g는 k번 밭의 거둔 양을 g만큼 늘린다. water와 pick은 작물을 한 번이라도 심은 밭에만 주어진다. 첫 줄에 n과 명령의 수 q가 빈칸 하나로 띄워 주어지고, 이어지는 q줄에 명령이 한 줄에 하나씩 주어진다. 명령을 차례로 모두 처리한 뒤, 1번 밭부터 차례로 한 줄에 하나씩 작물 이름, 물 준 횟수, 거둔 양을 빈칸 하나씩 띄워 출력하라.

입력
1 ≤ n ≤ 100, 1 ≤ q ≤ 1,000, 1 ≤ k ≤ n, 1 ≤ g ≤ 1,000.
작물 이름은 영어 소문자로만 된 1글자 이상 10글자 이하의 문자열이다
출력
n줄: 밭마다 작물 이름, 물 준 횟수, 거둔 양(쉼표 없이 숫자만)
예시 1 · stdin
4 9
plant 2 carrot
water 2
water 2
pick 2 300
plant 4 corn
water 4
plant 2 bean
water 2
pick 2 50
stdout
- 0 0
bean 1 350
- 0 0
corn 1 0
main.py
입력(stdin)

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

$ 준비됐어요

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

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

여러 값을 묶은 기록을 목록에 n개 담는 문제예요.
기록은 Python 사전 {"crop": "-", "water": 0, "total": 0}, JS 객체, TS는 interface Plot으로 모양을 적은 객체, Java·C# class Plot, C·C++ struct Plot, 크레이콘은 사전()으로 만들어요.
기록을 칸마다 따로 만드는 법: Python [{...} for _ in range(n)], JS·TS Array.from({ length: n }, () => ({...})), Java·C#은 new Plot[n] 뒤에 반복문으로 칸마다 new Plot(), C++ std::vector<Plot> plots(n), C는 struct Plot plots[100], 크레이콘은 반복문에서 plots.넣기(새밭()).
C와 C++는 배열·벡터 안에 기록이 통째로 들어 있고, 나머지 언어는 목록 칸이 기록을 가리켜요.
함정 셋: ① 기록 하나를 만들어 n칸에 채우면 모든 칸이 같은 기록 하나를 가리켜서, 한 밭을 고치면 모든 밭이 바뀌어요(예시가 네 줄 모두 bean 1 350으로).
Python [{...}] * n, JS Array(n).fill({...}), Java Arrays.fill(plots, new Plot()), 크레이콘 새목록(n, 새밭())이 모두 그래요.
② Java에서 new Plot[n]만 하고 기록을 넣지 않으면 칸이 모두 null이라, 첫 명령에서 NullPointerException으로 멈춰요.
③ 반대로 C·C++와 C#의 struct는 꺼내면 복사돼요.
C struct Plot p = plots[k - 1];, C++ Plot plot = plots[k - 1];, C#에서 Plot을 struct로 만들고 Plot plot = plots[k - 1];이라고 쓴 뒤 고치면 복사본만 바뀌고 목록 안의 기록은 그대로예요(예시가 네 줄 모두 - 0 0으로).
C는 포인터 &plots[k - 1], C++는 참조 Plot& plot으로 받고, C#은 class로 만들어요.

Pythonmain.py · 18 줄
n, q = map(int, input().split()) # 밭마다 기록(사전)을 따로 하나씩 만든다. 반복할 때마다 새 사전이 생긴다plots = [{"crop": "-", "water": 0, "total": 0} for _ in range(n)] for _ in range(q):    cmd = input().split()    plot = plots[int(cmd[1]) - 1]  # 복사가 아니라 목록 안의 그 기록을 가리킨다    if cmd[0] == "plant":        plot["crop"] = cmd[2]        plot["water"] = 0    elif cmd[0] == "water":        plot["water"] += 1    else:        plot["total"] += int(cmd[2]) for plot in plots:    print(plot["crop"], plot["water"], plot["total"])
JavaScriptmain.js · 20 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [n, q] = lines[0].trim().split(/\s+/).map(Number); // 밭마다 기록(객체)을 따로 하나씩 만든다. Array.from은 칸마다 함수를 불러 새 객체를 만든다const plots = Array.from({ length: n }, () => ({ crop: "-", water: 0, total: 0 })); for (let i = 1; i <= q; i++) {  const cmd = lines[i].trim().split(/\s+/);  const plot = plots[Number(cmd[1]) - 1]; // 복사가 아니라 목록 안의 그 기록을 가리킨다  if (cmd[0] === "plant") {    plot.crop = cmd[2];    plot.water = 0;  } else if (cmd[0] === "water") {    plot.water += 1;  } else {    plot.total += Number(cmd[2]);  }} console.log(plots.map((p) => `${p.crop} ${p.water} ${p.total}`).join("\n"));
TypeScriptmain.ts · 28 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const [n, q]: number[] = lines[0].trim().split(/\s+/).map(Number); // 기록의 모양을 타입으로 적어 둔다interface Plot {  crop: string;  water: number;  total: number;} // 밭마다 기록(객체)을 따로 하나씩 만든다. Array.from은 칸마다 함수를 불러 새 객체를 만든다const plots: Plot[] = Array.from({ length: n }, (): Plot => ({ crop: "-", water: 0, total: 0 })); for (let i = 1; i <= q; i++) {  const cmd: string[] = lines[i].trim().split(/\s+/);  const plot: Plot = plots[Number(cmd[1]) - 1]; // 복사가 아니라 목록 안의 그 기록을 가리킨다  if (cmd[0] === "plant") {    plot.crop = cmd[2];    plot.water = 0;  } else if (cmd[0] === "water") {    plot.water += 1;  } else {    plot.total += Number(cmd[2]);  }} console.log(plots.map((p: Plot) => `${p.crop} ${p.water} ${p.total}`).join("\n"));
JavaMain.java · 42 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringTokenizer; public class Main {    // 밭 하나의 기록    static class Plot {        String crop = "-";        int water = 0;        int total = 0;    }     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        StringTokenizer st = new StringTokenizer(in.readLine());        int n = Integer.parseInt(st.nextToken());        int q = Integer.parseInt(st.nextToken());         // new Plot[n]은 칸만 만든다(모두 null). 칸마다 new Plot()으로 기록을 따로 만들어 넣는다        Plot[] plots = new Plot[n];        for (int i = 0; i < n; i++) plots[i] = new Plot();         for (int i = 0; i < q; i++) {            st = new StringTokenizer(in.readLine());            String cmd = st.nextToken();            Plot plot = plots[Integer.parseInt(st.nextToken()) - 1]; // 복사가 아니라 그 기록을 가리킨다            if (cmd.equals("plant")) {                plot.crop = st.nextToken();                plot.water = 0;            } else if (cmd.equals("water")) {                plot.water++;            } else {                plot.total += Integer.parseInt(st.nextToken());            }        }         StringBuilder out = new StringBuilder();        for (Plot p : plots) out.append(p.crop).append(' ').append(p.water).append(' ').append(p.total).append('\n');        System.out.print(out);    }}
C#Main.cs · 40 줄
using System;using System.Text; // 밭 하나의 기록. class이므로 변수에 담으면 복사되지 않고 같은 기록을 가리킨다class Plot{    public string Crop = "-";    public int Water = 0;    public int Total = 0;} class Program{    static void Main()    {        string[] first = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int n = int.Parse(first[0]), q = int.Parse(first[1]);         // new Plot[n]은 칸만 만든다(모두 null). 칸마다 new Plot()으로 기록을 따로 만들어 넣는다        var plots = new Plot[n];        for (int i = 0; i < n; i++) plots[i] = new Plot();         for (int i = 0; i < q; i++)        {            string[] cmd = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            Plot plot = plots[int.Parse(cmd[1]) - 1];            if (cmd[0] == "plant")            {                plot.Crop = cmd[2];                plot.Water = 0;            }            else if (cmd[0] == "water") plot.Water++;            else plot.Total += int.Parse(cmd[2]);        }         var sb = new StringBuilder();        foreach (Plot p in plots) sb.Append($"{p.Crop} {p.Water} {p.Total}\n");        Console.Write(sb);    }}
C++main.cpp · 37 줄
#include <iostream>#include <string>#include <vector> // 밭 하나의 기록struct Plot {    std::string crop = "-";    int water = 0;    int total = 0;}; int main() {    int n, q;    std::cin >> n >> q;    // vector<Plot>(n)은 기록 n개를 따로따로 만든다    std::vector<Plot> plots(n);     for (int i = 0; i < q; i++) {        std::string cmd;        int k;        std::cin >> cmd >> k;        // &를 붙여 참조로 받아야 목록 안의 그 기록을 고친다. &가 없으면 복사본이다        Plot& plot = plots[k - 1];        if (cmd == "plant") {            std::cin >> plot.crop;            plot.water = 0;        } else if (cmd == "water") {            plot.water++;        } else {            int g;            std::cin >> g;            plot.total += g;        }    }     for (const Plot& p : plots) std::cout << p.crop << ' ' << p.water << ' ' << p.total << '\n';}
Cmain.c · 42 줄
#include <stdio.h>#include <string.h> /* 밭 하나의 기록 */struct Plot {    char crop[11];    int water;    int total;}; int main(void) {    int n, q;    /* 구조체 배열은 기록 n개가 통째로 나란히 들어 있다 */    static struct Plot plots[100];    scanf("%d %d", &n, &q);    for (int i = 0; i < n; i++) {        strcpy(plots[i].crop, "-");        plots[i].water = 0;        plots[i].total = 0;    }     for (int i = 0; i < q; i++) {        char cmd[8];        int k;        scanf("%7s %d", cmd, &k);        /* 포인터로 배열 안의 그 기록을 가리킨다. struct Plot p = plots[k - 1]; 은 복사본이다 */        struct Plot *plot = &plots[k - 1];        if (strcmp(cmd, "plant") == 0) {            scanf("%10s", plot->crop);            plot->water = 0;        } else if (strcmp(cmd, "water") == 0) {            plot->water++;        } else {            int g;            scanf("%d", &g);            plot->total += g;        }    }     for (int i = 0; i < n; i++) printf("%s %d %d\n", plots[i].crop, plots[i].water, plots[i].total);    return 0;}
Craykonmain.cray · 44 줄
// 밭 하나의 기록을 새로 만든다. 부를 때마다 새 사전이 생긴다새밭(){    p = 사전();    p["crop"] = "-";    p["water"] = 0;    p["total"] = 0;    돌려주기 p;} 첫줄 = 콘솔.수들읽기();n = 첫줄[0];q = 첫줄[1]; // 칸마다 기록을 따로 만들어 넣는다plots = [];반복 (i = 0; i < n; i++){    plots.넣기(새밭());} 반복 (i = 0; i < q; i++){    cmd = 콘솔.줄읽기().공백제거().나누기();    plot = plots[cmd[1].수로변환() - 1]; // 복사가 아니라 목록 안의 그 기록을 가리킨다    만약 (cmd[0] == "plant")    {        plot["crop"] = cmd[2];        plot["water"] = 0;    }    아니면 만약 (cmd[0] == "water")    {        plot["water"] += 1;    }    아니면    {        plot["total"] += cmd[2].수로변환();    }} 각각 (p 에서 plots){    콘솔.쓰기(p["crop"] + " " + p["water"] + " " + p["total"]);}