当前位置: 首页 > news >正文

【华为OD】石头剪刀布游戏

在这里插入图片描述

【华为OD】石头剪刀布游戏

题目描述

石头剪刀布游戏有3种出拳形状:石头、剪刀、布。分别用字母 A、B、C 表示。

游戏规则:

  1. 出拳形状之间的胜负规则如下:A > B;B > C;C > A;">"左边一个字母,表示相对优势形状,右边一个字母,表示相对劣势形状。
  2. 当本场次中有且仅有一种出拳形状优于其它出拳形状,则该形状的玩家是胜利者。否则认为是平局。
  3. 当发生平局,没有赢家。有多个胜利者时,同为赢家。

例如1: 三个玩家出拳分别是A、B、C,由于出现三方优势循环(即没有任何一方优于其它出拳者),判断为平局。

例如2: 三个玩家,出拳分别是A、B,出拳A的获胜。

例如3: 三个玩家,出拳全部是A,判为平局。

输入描述

在一场游戏中,每个玩家的信息为一行。玩家数量不超过1000。每个玩家信息有2个字段,用空格隔开:

  1. 玩家ID:一个仅由英文字母和数字组成的字符串
  2. 出拳形状:以英文大写字母表示,A、B、C形状。

例:

abc1 A
xyz B

解释:玩家abc1出拳为石头(A)。玩家xyz出拳为剪刀(B)

输出描述

输出为赢家的玩家ID列表(一个或多个),每个ID一行,按字符串升序排列。如果没有赢家,输出为"NULL"字符串。

示例

示例一

输入:

abc1 A
xyz B

输出:

abc1

说明: A比B有优势,abc1胜出

示例二

输入:

abc1 A
xyz A

输出:

NULL

说明: 没有优胜的出拳形状,平局

示例三

输入:

abc1 A
def A
alic A
xyz B

输出:

abc1
alic
def

说明: A为优胜方,有三个赢家。

解题思路

这道题的核心是理解石头剪刀布的胜负规则,并判断是否存在唯一的获胜形状。

关键点:

  1. A > B,B > C,C > A(循环克制关系)
  2. 只有当场上存在且仅存在一种形状能够克制其他所有形状时,该形状的玩家才获胜
  3. 如果出现循环克制(如A、B、C都存在)或所有玩家出拳相同,则平局

解法一:统计形状种类判断

思路讲解

这种方法通过统计场上出现的不同形状种类来判断胜负:

  1. 如果只有一种形状,平局
  2. 如果有两种形状,根据克制关系判断获胜方
  3. 如果有三种形状,形成循环克制,平局

Java实现

import java.util.*;public class RockPaperScissors {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);List<String> players = new ArrayList<>();Map<String, Character> playerMoves = new HashMap<>();Set<Character> moves = new HashSet<>();String line;while (scanner.hasNextLine() && !(line = scanner.nextLine()).isEmpty()) {String[] parts = line.split(" ");String playerId = parts[0];char move = parts[1].charAt(0);players.add(playerId);playerMoves.put(playerId, move);moves.add(move);}// 判断获胜情况if (moves.size() == 1 || moves.size() == 3) {// 平局情况:只有一种形状或三种形状都存在System.out.println("NULL");} else {// 两种形状,判断获胜方Character[] moveArray = moves.toArray(new Character[0]);char move1 = moveArray[0];char move2 = moveArray[1];char winningMove = getWinner(move1, move2);// 收集获胜玩家并排序List<String> winners = new ArrayList<>();for (String player : players) {if (playerMoves.get(player) == winningMove) {winners.add(player);}}Collections.sort(winners);for (String winner : winners) {System.out.println(winner);}}scanner.close();}private static char getWinner(char move1, char move2) {if ((move1 == 'A' && move2 == 'B') || (move1 == 'B' && move2 == 'C') || (move1 == 'C' && move2 == 'A')) {return move1;} else {return move2;}}
}

Python实现

import sysdef get_winner(move1, move2):if (move1 == 'A' and move2 == 'B') or \(move1 == 'B' and move2 == 'C') or \(move1 == 'C' and move2 == 'A'):return move1else:return move2def main():players = []player_moves = {}moves = set()for line in sys.stdin:line = line.strip()if not line:breakparts = line.split()player_id = parts[0]move = parts[1]players.append(player_id)player_moves[player_id] = movemoves.add(move)# 判断获胜情况if len(moves) == 1 or len(moves) == 3:print("NULL")else:# 两种形状,判断获胜方move_list = list(moves)winning_move = get_winner(move_list[0], move_list[1])# 收集获胜玩家并排序winners = [player for player in players if player_moves[player] == winning_move]winners.sort()for winner in winners:print(winner)if __name__ == "__main__":main()

C++实现

#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <string>using namespace std;char getWinner(char move1, char move2) {if ((move1 == 'A' && move2 == 'B') || (move1 == 'B' && move2 == 'C') || (move1 == 'C' && move2 == 'A')) {return move1;} else {return move2;}
}int main() {vector<string> players;map<string, char> playerMoves;set<char> moves;string line;while (getline(cin, line) && !line.empty()) {size_t spacePos = line.find(' ');string playerId = line.substr(0, spacePos);char move = line[spacePos + 1];players.push_back(playerId);playerMoves[playerId] = move;moves.insert(move);}// 判断获胜情况if (moves.size() == 1 || moves.size() == 3) {cout << "NULL" << endl;} else {// 两种形状,判断获胜方vector<char> moveVec(moves.begin(), moves.end());char winningMove = getWinner(moveVec[0], moveVec[1]);// 收集获胜玩家并排序vector<string> winners;for (const string& player : players) {if (playerMoves[player] == winningMove) {winners.push_back(player);}}sort(winners.begin(), winners.end());for (const string& winner : winners) {cout << winner << endl;}}return 0;
}

解法二:直接克制关系判断

思路讲解

这种方法直接根据克制关系来判断:

  1. 统计每种形状的出现次数
  2. 检查是否存在一种形状能够克制场上所有其他形状
  3. 如果存在这样的形状,该形状的玩家获胜;否则平局

这种方法更直观地体现了石头剪刀布的克制关系。

Java实现

import java.util.*;public class RockPaperScissorsV2 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);List<String> players = new ArrayList<>();Map<String, Character> playerMoves = new HashMap<>();Map<Character, Integer> moveCount = new HashMap<>();String line;while (scanner.hasNextLine() && !(line = scanner.nextLine()).isEmpty()) {String[] parts = line.split(" ");String playerId = parts[0];char move = parts[1].charAt(0);players.add(playerId);playerMoves.put(playerId, move);moveCount.put(move, moveCount.getOrDefault(move, 0) + 1);}// 检查获胜条件char winningMove = findWinningMove(moveCount);if (winningMove == 'X') {System.out.println("NULL");} else {// 收集获胜玩家并排序List<String> winners = new ArrayList<>();for (String player : players) {if (playerMoves.get(player) == winningMove) {winners.add(player);}}Collections.sort(winners);for (String winner : winners) {System.out.println(winner);}}scanner.close();}private static char findWinningMove(Map<Character, Integer> moveCount) {boolean hasA = moveCount.containsKey('A');boolean hasB = moveCount.containsKey('B');boolean hasC = moveCount.containsKey('C');// A克制B,如果有A和B但没有C,A获胜if (hasA && hasB && !hasC) return 'A';// B克制C,如果有B和C但没有A,B获胜if (hasB && hasC && !hasA) return 'B';// C克制A,如果有C和A但没有B,C获胜if (hasC && hasA && !hasB) return 'C';// 其他情况都是平局return 'X';}
}

Python实现

import sys
from collections import defaultdictdef find_winning_move(move_count):has_a = 'A' in move_counthas_b = 'B' in move_counthas_c = 'C' in move_count# A克制B,如果有A和B但没有C,A获胜if has_a and has_b and not has_c:return 'A'# B克制C,如果有B和C但没有A,B获胜if has_b and has_c and not has_a:return 'B'# C克制A,如果有C和A但没有B,C获胜if has_c and has_a and not has_b:return 'C'# 其他情况都是平局return Nonedef main():players = []player_moves = {}move_count = defaultdict(int)for line in sys.stdin:line = line.strip()if not line:breakparts = line.split()player_id = parts[0]move = parts[1]players.append(player_id)player_moves[player_id] = movemove_count[move] += 1# 检查获胜条件winning_move = find_winning_move(move_count)if winning_move is None:print("NULL")else:# 收集获胜玩家并排序winners = [player for player in players if player_moves[player] == winning_move]winners.sort()for winner in winners:print(winner)if __name__ == "__main__":main()

C++实现

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <string>using namespace std;char findWinningMove(const map<char, int>& moveCount) {bool hasA = moveCount.find('A') != moveCount.end();bool hasB = moveCount.find('B') != moveCount.end();bool hasC = moveCount.find('C') != moveCount.end();// A克制B,如果有A和B但没有C,A获胜if (hasA && hasB && !hasC) return 'A';// B克制C,如果有B和C但没有A,B获胜if (hasB && hasC && !hasA) return 'B';// C克制A,如果有C和A但没有B,C获胜if (hasC && hasA && !hasB) return 'C';// 其他情况都是平局return 'X';
}int main() {vector<string> players;map<string, char> playerMoves;map<char, int> moveCount;string line;while (getline(cin, line) && !line.empty()) {size_t spacePos = line.find(' ');string playerId = line.substr(0, spacePos);char move = line[spacePos + 1];players.push_back(playerId);playerMoves[playerId] = move;moveCount[move]++;}// 检查获胜条件char winningMove = findWinningMove(moveCount);if (winningMove == 'X') {cout << "NULL" << endl;} else {// 收集获胜玩家并排序vector<string> winners;for (const string& player : players) {if (playerMoves[player] == winningMove) {winners.push_back(player);}}sort(winners.begin(), winners.end());for (const string& winner : winners) {cout << winner << endl;}}return 0;
}

总结

两种解法都能正确解决问题:

  • 解法一通过统计形状种类数量来判断,逻辑简单清晰
  • 解法二直接根据克制关系判断,更符合游戏规则的直观理解

时间复杂度都是O(n),空间复杂度也是O(n),其中n是玩家数量。在实际应用中,两种方法都是可行的,可以根据个人喜好选择。

http://www.dtcms.com/a/393529.html

相关文章:

  • LinuxC++项目开发日志——基于正倒排索引的boost搜索引擎(1——项目框架)
  • Photoshop - Photoshop 非破坏性编辑
  • C++入门小馆:C++11第三弹(可变参数模板)
  • 常用设计模式中的工厂模式,责任链模式,策略模式和单例模式的简单说明
  • aave v3 合约解析1 存款
  • autosar中自旋锁和互斥锁的应用
  • 建筑可视化告别“假”渲染:用Photoshop+Twinmotion打造照片级场景
  • 一键生成linux服务器健康巡检html报告
  • 数据结构(C语言篇):(十八)交换排序
  • Ubuntu20.04下跑通ORB-SLAM2
  • C++二进制转十进制
  • WordPress用户系统 + JWT认证:打造统一的应用登录解决方案
  • PortSwigger靶场之将反射型 XSS 注入到带有尖括号和双引号的 JavaScript 字符串中,并使用 HTML 编码和单引号进行转义通关秘籍
  • win11电脑按键失灵,提供几个可能恢复的方法
  • Android 中获取稳定时间的方法
  • mac编译ffmpeg
  • Deepsoil V7.1.10+Shake2000,最新版程序、教学视频、PDF使用手册
  • Apollo相机数据RTMP推流与播放指南
  • 使用Python扩展Unity编辑器
  • 【Android】自定义控件
  • 探索 Event 框架 6:高级特性与性能优化
  • JavaSE基础——第九章 枚举类注解
  • 云计算在金融领域中的应用
  • 【入门算法】前缀和:先预存再求和,以空间换时间
  • mac编译vst3sdk
  • Java 网络原理(二)--- TCP的机制 + IP协议 +以太网协议 + DNS
  • Python文件名编码处理深度解析:绕过编码问题的专业指南
  • 如何利用简单的浏览器插件Web Scraper爬取知乎评论数据
  • 鹿鼎记豪侠传:Rust 重塑 iOS 江湖(下)
  • 03.博客版-镜像