{ }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()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

生徒ごとに今数えている票を辞書に置き、新しい票が来たらその値を上書きすれば済みます。
上書きする方法と「上書きしない」方法が多くの言語で似た形をしているのが落とし穴です。
Python d[k] = v、JS・TS map.set(k, v)、Craykon 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.個数);