{ }codelper
사전 고치기사전으로 세기P0228

마지막 표만 세는 투표

학급 회장 선거를 휴대폰으로 투표한다. 투표 기간에는 같은 학생이 몇 번이든 다시 투표할 수 있고, 학생마다 가장 마지막에 낸 표 하나만 센다. 첫 줄에 후보 수 k가, 둘째 줄에 후보 이름 k개가 빈칸 하나씩 띄워 주어진다. 셋째 줄에 들어온 표의 수 n이, 다음 n줄에 들어온 차례대로 표마다 "학생번호 후보이름"이 빈칸 하나로 띄워 주어진다. 학생번호는 문자열 그대로 비교한다.
그래서 "1"과 "01"은 다른 학생이다. 후보마다 한 줄에 후보 이름과 받은 표의 수를 빈칸 하나로 띄워, 둘째 줄에 나온 후보 차례대로 출력하라. 표를 하나도 받지 못한 후보도 0으로 출력한다. 마지막 줄에 표가 세어진 학생의 수(서로 다른 학생번호의 수)를 출력하라.

입력
1 ≤ k ≤ 20, 1 ≤ n ≤ 5,000.
후보 이름은 서로 다른 영어 소문자 1~10글자다.
학생번호는 영어 소문자와 숫자로 된 1~8글자다.
표의 후보이름은 늘 후보 가운데 하나다
출력
k줄(후보 이름, 표의 수), 그다음 한 줄(학생 수)
예시 1 · stdin
3
mina joon hana
5
s1 mina
s2 joon
s1 hana
s3 joon
s2 mina
stdout
mina 1
joon 1
hana 1
3
main.py
입력(stdin)

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

$ 준비됐어요

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

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

학생마다 지금 센 표를 사전에 두고, 새 표가 오면 그 값을 덮어쓰면 돼요.
덮어쓰는 방법과 '덮어쓰지 않는' 방법이 언어마다 비슷하게 생겨서 함정이에요.
Python d[k] = v, JS·TS map.set(k, v), 크레이콘 d[k] = v는 있던 값을 바꿔요.
Java put도 덮어쓰지만 putIfAbsent는 열쇠가 없을 때만 넣어요.
C# 인덱서 d[k] = v는 덮어쓰지만 d.Add(k, v)는 이미 있는 열쇠에서 ArgumentException을 던져요.
C++ m[k] = v는 덮어쓰지만 m.insert({k, v})와 emplace는 열쇠가 이미 있으면 아무것도 하지 않아서 첫 표가 남아요.
다 받은 다음 사전의 값만 돌며 후보마다 세면 표를 옮길 때 예전 후보에서 1을 빼는 일을 잊을 걱정이 없어요.
학생번호는 문자열로 둬요.
JS에서 Number로 바꾸면 "1"과 "01"이 한 학생이 돼요.
C에는 사전이 없어서 학생번호를 배열에 적고 strcmp로 앞에서부터 찾아요.

Pythonmain.py · 13 줄
k = int(input())cands = input().split()n = int(input())vote = {}                       # 학생 번호 → 지금 센 표for _ in range(n):    voter, cand = input().split()    vote[voter] = cand          # 있던 표는 덮어쓴다count = {c: 0 for c in cands}for cand in vote.values():    count[cand] += 1for c in cands:    print(c, count[c])print(len(vote))
JavaScriptmain.js · 18 줄
const tok = require("fs").readFileSync(0, "utf8").trim().split(/\s+/);let p = 0;const k = Number(tok[p++]);const cands = tok.slice(p, p + k);p += k;const n = Number(tok[p++]);// 학생 번호는 문자열 그대로 둔다("01"과 "1"은 다른 학생)const vote = new Map();for (let i = 0; i < n; i++) {  const voter = tok[p++];  const cand = tok[p++];  vote.set(voter, cand); // set은 있던 값을 덮어쓴다}const count = new Map(cands.map((c) => [c, 0]));for (const cand of vote.values()) count.set(cand, count.get(cand) + 1);const out = cands.map((c) => `${c} ${count.get(c)}`);out.push(String(vote.size));console.log(out.join("\n"));
TypeScriptmain.ts · 18 줄
import { readFileSync } from "node:fs";const tok: string[] = readFileSync(0, "utf8").trim().split(/\s+/);let p = 0;const k: number = Number(tok[p++]);const cands: string[] = tok.slice(p, p + k);p += k;const n: number = Number(tok[p++]);const vote = new Map<string, string>();for (let i = 0; i < n; i++) {  const voter: string = tok[p++];  const cand: string = tok[p++];  vote.set(voter, cand); // set은 있던 값을 덮어쓴다}const count = new Map<string, number>(cands.map((c): [string, number] => [c, 0]));for (const cand of vote.values()) count.set(cand, (count.get(cand) ?? 0) + 1);const out: string[] = cands.map((c) => `${c} ${count.get(c)}`);out.push(String(vote.size));console.log(out.join("\n"));
JavaMain.java · 28 줄
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.HashMap;import java.util.Map;import java.util.StringTokenizer; public class Main {    public static void main(String[] args) throws Exception {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int k = Integer.parseInt(br.readLine().trim());        String[] cands = br.readLine().trim().split("\\s+");        int n = Integer.parseInt(br.readLine().trim());        Map<String, String> vote = new HashMap<>();        for (int i = 0; i < n; i++) {            StringTokenizer st = new StringTokenizer(br.readLine());            String voter = st.nextToken();            String cand = st.nextToken();            vote.put(voter, cand); // put은 덮어쓴다(putIfAbsent는 처음 값을 지킨다)        }        Map<String, Integer> count = new HashMap<>();        for (String c : cands) count.put(c, 0);        for (String cand : vote.values()) count.merge(cand, 1, Integer::sum);        StringBuilder out = new StringBuilder();        for (String c : cands) out.append(c).append(' ').append(count.get(c)).append('\n');        out.append(vote.size()).append('\n');        System.out.print(out);    }}
C#Main.cs · 27 줄
using System;using System.Collections.Generic;using System.Text; class Program{    static void Main()    {        int k = int.Parse(Console.ReadLine().Trim());        string[] cands = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int n = int.Parse(Console.ReadLine().Trim());        var vote = new Dictionary<string, string>();        for (int i = 0; i < n; i++)        {            string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            // 인덱서 대입은 덮어쓴다. Add는 이미 있는 열쇠에서 예외를 던진다            vote[p[0]] = p[1];        }        var count = new Dictionary<string, int>();        foreach (string c in cands) count[c] = 0;        foreach (string cand in vote.Values) count[cand]++;        var sb = new StringBuilder();        foreach (string c in cands) sb.Append(c).Append(' ').Append(count[c]).Append('\n');        sb.Append(vote.Count).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 23 줄
#include <iostream>#include <string>#include <unordered_map>#include <vector> int main() {    std::ios::sync_with_stdio(false);    int k, n;    std::cin >> k;    std::vector<std::string> cands(k);    for (auto& c : cands) std::cin >> c;    std::cin >> n;    std::unordered_map<std::string, std::string> vote;    for (int i = 0; i < n; i++) {        std::string voter, cand;        std::cin >> voter >> cand;        vote[voter] = cand; // operator[]는 덮어쓴다. insert·emplace는 있던 값을 그대로 둔다    }    std::unordered_map<std::string, int> count;    for (const auto& [voter, cand] : vote) count[cand]++;    for (const auto& c : cands) std::cout << c << ' ' << count[c] << '\n';    std::cout << vote.size() << '\n';}
Cmain.c · 32 줄
#include <stdio.h>#include <string.h> /* C에는 사전이 없어서, 학생 번호와 그 학생의 표(후보 번호)를 배열에 적고 앞에서부터 찾는다 */static char voters[5000][9];static int choice[5000];static char cands[20][11]; int main(void) {    int k, n, m = 0;    scanf("%d", &k);    for (int i = 0; i < k; i++) scanf("%10s", cands[i]);    scanf("%d", &n);    for (int i = 0; i < n; i++) {        char voter[16], cand[16];        scanf("%15s %15s", voter, cand);        int c = 0;        while (strcmp(cands[c], cand) != 0) c++;        int j = 0;        while (j < m && strcmp(voters[j], voter) != 0) j++;        if (j == m) {            strcpy(voters[m], voter);            m++;        }        choice[j] = c; /* 있던 표는 덮어쓴다 */    }    int count[20] = {0};    for (int j = 0; j < m; j++) count[choice[j]]++;    for (int i = 0; i < k; i++) printf("%s %d\n", cands[i], count[i]);    printf("%d\n", m);    return 0;}
Craykonmain.cray · 24 줄
k = 콘솔.줄읽기().수로변환();cands = 콘솔.줄읽기().공백제거().나누기(" ");n = 콘솔.줄읽기().수로변환();vote = 사전();반복 (i = 0; i < n; i++){    p = 콘솔.줄읽기().공백제거().나누기(" ");    // 같은 열쇠에 다시 넣으면 있던 표를 덮어쓴다    vote[p[0]] = p[1];}count = 사전();각각 (c 에서 cands){    count[c] = 0;}각각 (cand 에서 vote.값목록){    count[cand] = count[cand] + 1;}각각 (c 에서 cands){    콘솔.쓰기(c + " " + count[c]);}콘솔.쓰기(vote.개수);