机考E卷100分题 - 猜数字

题目描述

一个人设定一组四码的数字作为谜底,另一方猜。

每猜一个数,出数者就要根据这个数字给出提示,提示以XAYB形式呈现,直到猜中位置。

其中X表示位置正确的数的个数(数字正确且位置正确),而Y表示数字正确而位置不对的数的个数。

例如,当谜底为8123,而猜谜者猜1052时,出题者必须提示0A2B。

例如,当谜底为5637,而猜谜者才4931时,出题者必须提示1A0B。

当前已知N组猜谜者猜的数字与提示,如果答案确定,请输出答案,不确定则输出NA。

输入描述

第一行输入一个正整数,0<N < 100。

接下来N行,每一行包含一个猜测的数字与提示结果。

输出描述

输出最后的答案,答案不确定则输出NA。

示例1

输入

6
4815 1A1B
5716 0A1B
7842 0A1B
4901 0A0B
8585 3A0B
8555 2A1B
1234567

输出

3585
1

解题思路

暴力枚举所有可能的谜底,即0000~9999,然后用每一个谜底去匹配输入的猜测。如果当前谜底与输入的猜测产生的提示符合预期,则说明该谜底是可行的。如果某个谜底可以符合所有输入的猜测,那么该谜底就是题解。如果暴力枚举出来的所有谜底中只有一个可行的谜底,那么该谜底就是题解,否则本题无解,返回NA。

由于需要验证0000~9999这一万个可能的谜底,而每个谜底最多需要验证100个输入的猜测数字,因此该算法非常容易超时。为了优化算法,我们可以对输入的猜测进行剪枝处理。例如,当输入的猜测提示为0A0B时,我们可以排除所有包含输入数字的谜底,因为这些谜底与输入数字的位置和数字都不匹配。同样地,当输入的猜测提示为0A时,我们可以排除所有包含输入数字的位置的谜底,因为这些谜底与输入数字的位置不匹配。通过对输入的猜测进行剪枝处理,我们可以大大减少需要验证的谜底数量,从而提高算法效率。

Java

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(); // 输入猜测的次数

        // 存储所有猜测的数字和提示结果
        List<String[]> guessInfos = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            String guessNum = scanner.next(); // 输入猜测的数字
            String guessResult = scanner.next(); // 输入猜测的结果
            guessInfos.add(new String[]{guessNum, guessResult}); // 将猜测的数字和结果存入列表中
        }

        int validCount = 0; // 记录符合条件的答案数量
        String validAnswer = ""; // 存储符合条件的答案

        // 遍历所有可能的四位数
        for (int num = 0; num <= 9999; num++) {
            String answer = String.format("%04d", num); // 将数字格式化为四位数字符串
            boolean isValid = true; // 标记当前答案是否有效

            // 遍历每个猜测的数字和结果
            for (String[] guessInfo : guessInfos) {
                String guess = guessInfo[0]; // 获取猜测的数字
                String expectResult = guessInfo[1]; // 获取猜测的结果

                int countA = 0; // 记录数字和位置都正确的个数
                int countB = 0; // 记录数字正确但位置不正确的个数

                int[] answerArr = new int[10]; // 存储答案中每个数字出现的次数
                int[] guessArr = new int[10]; // 存储猜测中每个数字出现的次数

                // 遍历每个位置
                for (int i = 0; i < guess.length(); i++) {
                    int c1Int = guess.charAt(i) - '0'; // 获取猜测中该位置上的数字
                    int c2Int = answer.charAt(i) - '0'; // 获取答案中该位置上的数字

                    if (c1Int == c2Int) {
                        countA++; // 如果数字和位置都正确,countA+1
                    } else {
                        guessArr[c1Int]++; // 在 guessArr 中记录该数字出现的次数
                        answerArr[c2Int]++; // 在 answerArr 中记录该数字出现的次数
                    }
                }

                for (int i = 0; i < 10; i++) {
                    countB += Math.min(answerArr[i], guessArr[i]); // 计算数字正确但位置不正确的个数
                }

                String realResult = countA + "A" + countB + "B"; // 根据猜测和答案计算真实结果

                if (!realResult.equals(expectResult)) {
                    isValid = false; // 如果真实结果和猜测结果不一致,标记当前答案为无效
                    break;
                }
            }

            if (isValid) {
                validCount++; // 如果当前答案有效,更新符合条件的答案数量
                validAnswer = answer; // 更新符合条件的答案

                if (validCount > 1) {
                    break; // 如果符合条件的答案数量大于1,跳出循环
                }
            }
        }

        if (validCount != 1) {
            System.out.println("NA"); // 如果符合条件的答案不唯一,输出 NA
        } else {
            System.out.println(validAnswer); // 如果符合条件的答案唯一,输出答案
        }
    }
}


123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778

Python


from typing import List, Tuple

def main():
    n = int(input())  # 输入猜测的次数

    # 存储所有猜测的数字和提示结果
    guess_infos = [tuple(input().split()) for _ in range(n)]

    valid_count = 0  # 记录符合条件的答案数量
    valid_answer = ""  # 存储符合条件的答案

    # 遍历所有可能的四位数
    for num in range(10000):
        answer = f"{num:04d}"  # 将数字格式化为四位数字符串
        is_valid = True  # 标记当前答案是否有效

        # 遍历每个猜测的数字和结果
        for guess, expect_result in guess_infos:
            count_a = 0  # 记录数字和位置都正确的个数
            count_b = 0  # 记录数字正确但位置不正确的个数

            answer_arr = [0] * 10  # 存储答案中每个数字出现的次数
            guess_arr = [0] * 10  # 存储猜测中每个数字出现的次数

            # 遍历每个位置
            for i in range(len(guess)):
                c1_int = int(guess[i])  # 获取猜测中该位置上的数字
                c2_int = int(answer[i])  # 获取答案中该位置上的数字

                if c1_int == c2_int:
                    count_a += 1  # 如果数字和位置都正确,countA+1
                else:
                    guess_arr[c1_int] += 1  # 在 guessArr 中记录该数字出现的次数
                    answer_arr[c2_int] += 1  # 在 answerArr 中记录该数字出现的次数

            count_b = sum(min(answer_arr[i], guess_arr[i]) for i in range(10))  # 计算数字正确但位置不正确的个数

            real_result = f"{count_a}A{count_b}B"  # 根据猜测和答案计算真实结果

            if real_result != expect_result:
                is_valid = False  # 如果真实结果和猜测结果不一致,标记当前答案为无效
                break

        if is_valid:
            valid_count += 1  # 如果当前答案有效,更新符合条件的答案数量
            valid_answer = answer  # 更新符合条件的答案

            if valid_count > 1:
                break  # 如果符合条件的答案数量大于1,跳出循环

    if valid_count != 1:
        print("NA")  # 如果符合条件的答案不唯一,输出 NA
    else:
        print(valid_answer)  # 如果符合条件的答案唯一,输出答案

if __name__ == "__main__":
    main()


123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960

JavaScript

// 引入readline库,用于从标准输入读取数据
const readline = require('readline');
// 创建readline接口实例
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

// 定义变量n来存储猜测的总数
let n;
// 定义数组来存储每次的猜测数字和结果
let guessInfos = [];

// 监听行输入事件
rl.on('line', (line) => {
  if (!n) {
    // 如果n未定义,读取第一行作为猜测总数
    n = parseInt(line.trim());
  } else {
    // 否则读取猜测数字和相应的结果,并存入guessInfos数组
    const [guessNum, guessResult] = line.split(' ');
    guessInfos.push([guessNum, guessResult]);
    if (guessInfos.length === n) {
      // 当读取完所有数据后关闭接口
      rl.close();
    }
  }
});

// 监听关闭事件,开始处理数据
rl.on('close', () => {
  // 用于记录符合条件的答案数量
  let validCount = 0;
  // 用于存储有效的答案
  let validAnswer = '';

  // 遍历0000到9999所有可能的答案
  for (let num = 0; num <= 9999; num++) {
    const answer = num.toString().padStart(4, '0');
    let isValid = true;

    // 遍历所有的猜测信息
    for (const [guess, expectResult] of guessInfos) {
      let countA = 0; // 位置和数字都正确的数量
      let countB = 0; // 数字正确但位置错误的数量
      // 初始化数字出现频次的数组
      const answerArr = new Array(10).fill(0);
      const guessArr = new Array(10).fill(0);

      // 对每个位置的数字进行比较
      for (let i = 0; i < guess.length; i++) {
        const c1Int = parseInt(guess[i]);
        const c2Int = parseInt(answer[i]);

        if (c1Int === c2Int) {
          countA++;
        } else {
          guessArr[c1Int]++;
          answerArr[c2Int]++;
        }
      }

      // 计算位置不正确但数字正确的数量
      for (let i = 0; i < 10; i++) {
        countB += Math.min(answerArr[i], guessArr[i]);
      }

      // 构造实际结果字符串
      const realResult = `${countA}A${countB}B`;

      // 如果实际结果与预期结果不匹配,该答案无效
      if (realResult !== expectResult) {
        isValid = false;
        break;
      }
    }

    // 如果该答案有效,记录下来
    if (isValid) {
      validCount++;
      validAnswer = answer;

      // 如果找到多于一个有效答案,则停止搜索
      if (validCount > 1) {
        break;
      }
    }
  }

  // 根据有效答案数量输出结果
  if (validCount !== 1) {
    console.log('NA');
  } else {
    console.log(validAnswer);
  }
});

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697

C++

#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include <sstream>

using namespace std;

int main() {
    int n;
    cin >> n; // 输入猜测的次数

    // 存储所有猜测的数字和提示结果
    vector<pair<string, string>> guessInfos;
    for (int i = 0; i < n; i++) {
        string guessNum, guessResult;
        cin >> guessNum >> guessResult; // 输入猜测的数字和结果
        guessInfos.push_back(make_pair(guessNum, guessResult)); // 将猜测的数字和结果存入列表中
    }

    int validCount = 0; // 记录符合条件的答案数量
    string validAnswer = ""; // 存储符合条件的答案

    // 遍历所有可能的四位数
    for (int num = 0; num <= 9999; num++) {
        stringstream ss;
        ss << setw(4) << setfill('0') << num;
        string answer = ss.str(); // 将数字格式化为四位数字符串
        bool isValid = true; // 标记当前答案是否有效

        // 遍历每个猜测的数字和结果
        for (const auto& guessInfo : guessInfos) {
            string guess = guessInfo.first; // 获取猜测的数字
            string expectResult = guessInfo.second; // 获取猜测的结果

            int countA = 0; // 记录数字和位置都正确的个数
            int countB = 0; // 记录数字正确但位置不正确的个数

            vector<int> answerArr(10, 0); // 存储答案中每个数字出现的次数
            vector<int> guessArr(10, 0); // 存储猜测中每个数字出现的次数

            // 遍历每个位置
            for (int i = 0; i < guess.length(); i++) {
                int c1Int = guess[i] - '0'; // 获取猜测中该位置上的数字
                int c2Int = answer[i] - '0'; // 获取答案中该位置上的数字

                if (c1Int == c2Int) {
                    countA++; // 如果数字和位置都正确,countA+1
                } else {
                    guessArr[c1Int]++; // 在 guessArr 中记录该数字出现的次数
                    answerArr[c2Int]++; // 在 answerArr 中记录该数字出现的次数
                }
            }

            for (int i = 0; i < 10; i++) {
                countB += min(answerArr[i], guessArr[i]); // 计算数字正确但位置不正确的个数
            }

            string realResult = to_string(countA) + "A" + to_string(countB) + "B"; // 根据猜测和答案计算真实结果

            if (realResult != expectResult) {
                isValid = false; // 如果真实结果和猜测结果不一致,标记当前答案为无效
                break;
            }
        }

        if (isValid) {
            validCount++; // 如果当前答案有效,更新符合条件的答案数量
            validAnswer = answer; // 更新符合条件的答案

            if (validCount > 1) {
                break; // 如果符合条件的答案数量大于1,跳出循环
            }
        }
    }

    if (validCount != 1) {
        cout << "NA" << endl; // 如果符合条件的答案不唯一,输出 NA
    } else {
        cout << validAnswer << endl; // 如果符合条件的答案唯一,输出答案
    }

    return 0;
}


1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586

C语言

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main() {
    int n;
    scanf("%d", &n); // 读取输入的猜测次数

    char guessNum[5], guessResult[5];
    char guessInfos[n][10][2][5]; // 创建数组存储每次的猜测和结果

    for (int i = 0; i < n; i++) {
        scanf("%s %s", guessNum, guessResult); // 读取每次的猜测数字和结果
        strcpy(guessInfos[i][0], guessNum);
        strcpy(guessInfos[i][1], guessResult);
    }

    int validCount = 0; // 用于记录符合条件的答案数量
    char validAnswer[5]; // 用于存储有效答案

    // 遍历所有可能的四位数
    for (int num = 0; num <= 9999; num++) {
        char answer[5];
        sprintf(answer, "%04d", num); // 将数字格式化为四位数字符串

        int isValid = 1; // 假设当前答案有效

        // 对每组猜测信息进行验证
        for (int j = 0; j < n; j++) {
            char *guess = guessInfos[j][0];
            char *expectResult = guessInfos[j][1];

            int countA = 0; // 位置和数字都正确的数量
            int countB = 0; // 数字正确位置错误的数量
            int answerArr[10] = {0};
            int guessArr[10] = {0};

            // 比较猜测数字和答案数字
            for (int i = 0; i < 4; i++) {
                int c1Int = guess[i] - '0';
                int c2Int = answer[i] - '0';

                if (c1Int == c2Int) {
                    countA++;
                } else {
                    guessArr[c1Int]++;
                    answerArr[c2Int]++;
                }
            }

            // 计算位置不对但数字正确的情况
            for (int i = 0; i < 10; i++) {
                countB += (answerArr[i] < guessArr[i]) ? answerArr[i] : guessArr[i];
            }

            char realResult[5];
            sprintf(realResult, "%dA%dB", countA, countB); // 构造实际的结果字符串

            if (strcmp(realResult, expectResult) != 0) {
                isValid = 0; // 如果实际结果和预期结果不符,标记为无效
                break;
            }
        }

        // 如果当前答案有效,记录下来
        if (isValid) {
            validCount++;
            strcpy(validAnswer, answer);

            if (validCount > 1) {
                break; // 如果找到多于一个有效答案,停止搜索
            }
        }
    }

    // 根据有效答案的数量输出结果
    if (validCount != 1) {
        printf("NA\n");
    } else {
        printf("%s\n", validAnswer);
    }

    return 0;
}

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
#华为##OD##牛客创作赏金赛#

主要记录自己的刷题日常,学而时习之。

全部评论

相关推荐

点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务