プログラミングコンテスト問題の解法と分析

患者の並び替え問題

患者が診察を受けに来院し、以下のルールに基づいて診察の順番を決定するプログラムを作成する。

  • 高齢者(年齢が60歳以上)は、若年者より優先される。
  • 高齢者は年齢が高い順に診察され、年齢が同じ場合は来院順に診察される。
  • 若年者は来院順に診察される。

解法のポイント

この問題は、カスタム比較ロジックを使用した構造体のソートをテストするものである。患者の情報を構造体で管理し、ソートアルゴリズム(ここでは標準ライブラリのstd::sortを使用)に比較関数を渡すのが効率的な方法である。

実装例(C++)

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

struct Patient {
    std::string id;
    int age;
    int arrivalOrder; // 来院順を記録するためのフィールド
};

// 比較関数
bool comparePatients(const Patient& a, const Patient& b) {
    bool isSeniorA = a.age >= 60;
    bool isSeniorB = b.age >= 60;

    // 高齢者は若年者より優先
    if (isSeniorA && !isSeniorB) {
        return true;
    }
    if (!isSeniorA && isSeniorB) {
        return false;
    }

    // 両方とも高齢者の場合、年齢が高い順
    if (isSeniorA && isSeniorB) {
        if (a.age != b.age) {
            return a.age > b.age;
        }
        // 年齢が同じなら来院順
        return a.arrivalOrder < b.arrivalOrder;
    }

    // 両方とも若年者の場合、来院順
    return a.arrivalOrder < b.arrivalOrder;
}

int main() {
    int patientCount;
    std::cin >> patientCount;

    std::vector<Patient> patients(patientCount);

    for (int i = 0; i < patientCount; ++i) {
        patients[i].id = "P" + std::to_string(i + 1); // IDを生成(例)
        std::cin >> patients[i].age;
        patients[i].arrivalOrder = i; // 来院順を記録
    }

    // カスタム比較関数でソート
    std::sort(patients.begin(), patients.end(), comparePatients);

    // 結果を出力
    for (const auto& p : patients) {
        std::cout << p.id << " " << p.age << std::endl;
    }

    return 0;
}

卓球のスコア計算

卓球の試合の各ポイントの勝敗(W:プレイヤーAの勝ち, L:プレイヤーBの勝ち)を記録した文字列が与えられる。この記録に基づき、11点制と21点制のそれぞれの試合結果を計算する。

解法のポイント

複数行の入力を一つの文字列に結合し、文字を一つずつ処理する。プレイヤーAとBのスコアをカウントし、どちらかのスコアが11点(または21点)に達し、かつ得点差が2以上になった時点でセットの結果を出力し、スコアをリセットする。入力の終わり('E')が検出されたら処理を終了する。

実装例(C++)

#include <iostream>
#include <string>

void calculateScore(const std::string& gameRecord, int targetScore) {
    int scoreA = 0, scoreB = 0;

    for (char c : gameRecord) {
        if (c == 'E') break;
        if (c == 'W') {
            scoreA++;
        } else if (c == 'L') {
            scoreB++;
        }

        // セットの終了条件をチェック
        if ((scoreA >= targetScore || scoreB >= targetScore) && std::abs(scoreA - scoreB) >= 2) {
            std::cout << scoreA << ":" << scoreB << std::endl;
            scoreA = 0;
            scoreB = 0;
        }
    }
    // 最後のセットの結果を出力
    std::cout << scoreA << ":" << scoreB << std::endl;
}

int main() {
    std::string fullRecord;
    std::string line;

    // 入力をすべて結合する
    while (std::cin >> line) {
        if (line.find('E') != std::string::npos) {
            fullRecord += line.substr(0, line.find('E'));
            break;
        }
        fullRecord += line;
    }

    // 11点制と21点制の結果を計算
    std::cout << "11点制の結果:" << std::endl;
    calculateScore(fullRecord, 11);
    std::cout << std::endl << "21点制の結果:" << std::endl;
    calculateScore(fullRecord, 21);

    return 0;
}

秘密の部屋の探索

2つのパスコード(10進数、最大63)が与えられる。これらを8ビットの2進数に変換し、ビットごとの論理積(AND)を計算する。結果の2進数の右から数えて、nビット目が1である場合、n番目の秘密の部屋を開けることができる。少なくとも2つの部屋を開けることができれば、大门を開けることができる。

解法のポイント

2つの10進数をビットセット(std::bitset)に変換し、ビット単位のAND演算を実行する。結果のビットセットをスキャンし、'1'のビットの位置(部屋の番号)を特定する。'1'のビットの総数が2以上であれば、大门を開けることができる。

実装例(C++)

#include <iostream>
#include <bitset>

int main() {
    int passcode1, passcode2;
    std::cin >> passcode1 >> passcode2;

    // 8ビットのビットセットに変換
    std::bitset<8> binary1(passcode1);
    std::bitset<8> binary2(passcode2);

    // ビットごとのAND演算
    std::bitset<8> result = binary1 & binary2;

    int openableRoomCount = 0;
    std::cout << "開けることができる部屋の番号: ";
    for (int i = 0; i < 8; ++i) {
        if (result[i] == 1) {
            // ビットの位置(0~7)を部屋の番号(1~8)に変換
            std::cout << (i + 1) << " ";
            openableRoomCount++;
        }
    }
    std::cout << std::endl;

    // 大门を開けることができるか判定
    if (openableRoomCount >= 2) {
        std::cout << "大门: Open" << std::endl;
    } else {
        std::cout << "大门: Close" << std::endl;
    }

    return 0;
}

タグ: C++ 構造体 ソート ビット演算 入力処理

7月24日 17:51 投稿