PTA-德州扑克 题解
于2020/02/24记录。
德州扑克属实是个带难题。本题解简单易懂,命名合理,应该比较好理解。
题目如下:
最近,阿夸迷于德州扑克。所以她找到了很多人和她一起玩。由于人数众多,阿夸必须更改游戏规则:
所有扑克牌均只看数字,不计花色。
每张卡的值为1、2、3、4、5、6、7、8、9、10、11、12、13 中的一种(对应A,2、3、4、5、6、7, 8、9、10,J,Q,K)
每位玩家从一副完整的扑克牌(没有大小王)中抽出五张扑克牌,可能出现的手牌的值从低到高排列如下:
高牌:不包含以下牌的牌。对于都是高牌的牌,按照五张牌的值的和进行从大到小排序。
对子:手中的5张牌中有2张相同值的牌。对于都拥有对子的牌,按构成该对子的牌的值进行从大到小地排序。如果这些都相同,则按手牌中余下3张牌的值的和进行从大到小排序。
两对:手中拥有两对不同的对子。对于都包含两对的手牌,按其最高对子的值进行从大到小排序。如果最高对子相同,则按另一个对子的值从大到小地进行排序。如果这些值相同,则按剩余牌的值从大到小地进行排序。
三条:手中拥有3张相同值的牌。对于都包含三条的手牌按构成三条的牌的值进行从大到小地排序。如果这些值相同,则按剩余牌的值从大到小地进行排序。
满堂红:手中拥有一个三条和一个对子。同理,先按三条大小排序,如果三条大小相同,则按对子大小进行排序。
四条:手中拥有4张相同值的牌。对于都包含四条的手牌按构成四条的牌的值进行从大到小地排序。如果这些值相同,则按剩余牌的值从大到小地进行排序。
顺子:手中拥有5张连续值的卡。对于都包含顺子的手牌按顺子最大的牌进行排序。
皇家同花顺:手中拥有10到A(10、J、Q、K、A)。是最大的手牌!
现在,阿夸已经知道了每个人的手牌,她想要知道所有人的排名列表。如果玩家的手牌大小相等,则按玩家名字的字典序输出。保证没有重复的名字。你能帮帮她吗?
输入格式:
第一行包含一个正整数 N (1<=N<=100000) ,表示玩家的人数。
接下来 N 行,每行包含两个字符串:m (1<=|m|<=10 ) ,表示玩家的名字;s (1<=|s|<=10),表示玩家的手牌。
输出格式:
输出 N个玩家的排名列表。
输入样例:
3
Alice AAA109
Bob 678910
Boa 678910
输出样例:
Boa
Bob
Alice
解:
头文件
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
本题包含一个结构体struct People、三个函数:①int trans(string str)②void deal_the_level_of(People x,int cur)③int cmp(People a,People b)、主函数:
struct People
{
string name;
string s;
int card[14];
double level;//大等级从1-8 细分等级顺序用小数点来算大小
}f[100005];
结构体的成员很简单:名字和手牌都为string类,方便输入输出和拆分;card数组分别储存这个人拥有的牌的情况;最后一个最重要的等级,我用了double型来定义,通过小数点来判定牌面大小的优先级;同时定义一个全局变量的数组方便后续输入和处理。
int trans(string str)
{
if(str=="A")return 1;
if(str=="2")return 2;
if(str=="3")return 3;
if(str=="4")return 4;
if(str=="5")return 5;
if(str=="6")return 6;
if(str=="7")return 7;
if(str=="8")return 8;
if(str=="9")return 9;
if(str=="10")return 10;
if(str=="J")return 11;
if(str=="Q")return 12;
if(str=="K")return 13;
}
trans函数的功能想必大家都不陌生,之前的白话文编程作业多次需要将字符串转化为有数值的数字,这个函数也是一个将string类的字符串转化为数字,即对应的牌面。
int cmp(People a,People b)
{
if(a.level!=b.level)return a.level>b.level;
else return a.name<b.name;
}
这个cmp(compare)函数是给后面要用的sort函数作为其第三个参数,说白了就是告诉sort怎么进行排序。本题是按照牌面从大到小来排,如果牌面相同就按照名字的字典序来排。由于本题用的是string类,进行字典序排序十分简单,一个小于号“<”就搞定。
下面是本题最重要的函数!!由于这个函数很长,有70多行,所以将解释放入注释中。
函数顾名思义--deal the level of (某个People型的变量):处理People型变量x的等级。
void deal_the_level_of(People x,int cur) //current 当前的那个下标
{
int single_value=0;//剩下单张牌总值的和
int couple1=0,couple2=0;//有一个对子 、有两个对子 其值为对子对应的牌面
int three=0; //判断是否有三条
int four=0; //判断是否有四条
bool line=false;//判断是否有顺子 有的话更为true
int maxn;//顺子中最大的牌
for(int i=1;i<=13;i++)
{
if(x.card[i]==1)//遇到这张牌是单张的
{
int judge=1,j;//判断顺子
for(j=i+1;j<=i+4;j++)judge*=x.card[j];//不断相乘,只有全都是 1 ,乘出来才会为1.
if(judge==1){//是顺子
line=true;
maxn=j-1;
break;
}
else single_value+=i;
}
if(x.card[i]==2)//如果这张牌拥有两张
{
if(couple1==0)couple1=i;//如果之前没出现过对子
else couple2=i;//之前出现过对子了,那这个就是第二个对子
}
if(x.card[i]==3)three=i;//如果这张牌拥有三张
if(x.card[i]>=4)//这张牌拥有四张或五张,一样的都归为 四条 这个级别。
{
four=i;
if(x.card[i]==5)single_value+=i;//五张一样的 剩下那张归为单张
}
}
/*
注意!如果一个大等级中,有多个排序的优先级
那么:
第一优先级 乘 0.01
第二优先级 0.0001
第三优先级 0.000001
因为最大的单张牌面“K”的值为13,超过10了,如果少乘一个0会影响到大等级。
*/
if(x.card[10]*x.card[11]*x.card[12]*x.card[13]*x.card[1]==1)x.level+=8.0;//皇家同花顺 ,永远滴神!
else if(line)//顺子 第7级
{
x.level=7.0;
x.level+=maxn*0.01;
}
else if(four)//四条 第6级
{
x.level=6.0;
x.level+=four*0.01+single_value*0.0001;
}
else if(three)//满堂红或三条
{
if(couple1){//有一个对子,满堂红 第5级
x.level=5.0;
x.level+=three*0.01+couple1*0.0001;
}
else{//三条 第4级
x.level=4.0;
x.level+=three*0.01+single_value*0.0001;
}
}
else if(couple1)//两对或对子
{
if(couple2){//两对 第3级
x.level=3.0;
x.level+=couple2*0.01+couple1*0.0001+single_value*0.000001;
}
else{//单个对子 第2级
x.level=2.0;
x.level+=couple1*0.01+single_value*0.0001;
}
}
else {//高牌 最弱的第1级
x.level=1.0;
x.level+=single_value*0.0001;
}
f[cur]=x;//不用指针,将其转移给当前的这个f (因为f数组是全局变量) ,不然f数组的值不会改变的
}
主函数:
解释还是放在注释里啦!
int main()
{
int n,value;
string tmp;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>f[i].name>>f[i].s;
string str=f[i].s;
for(int j=0,t=0;t<5;t++)//共五张牌
{
if(str[j]!='1'){ //不为10
tmp=str[j]; //提取出这个字符
value=trans(tmp);//转换这个字符为对应的值
f[i].card[value]++;//该值的手牌数+1
j++;
}
else{ //遇到10了,只有 10 才会出现 1这个数字,因为牌值为1的是 A
f[i].card[10]++;
j+=2; //跳两格
}
}
deal_the_level_of(f[i],i);//处理f[i],记得带下标i
}
sort(f,f+n,cmp); //排序
for(int i=0;i<n;i++)cout<<f[i].name<<endl; //输出
return 0;
}
我遇到的问题:
细节实在太多了,大量的分类情况堆在一起会十分混乱,所以在编写时最好用笔在一张草稿纸写出分类、优先级排序的思路。
一共有10个测试点,我的过程为:
通过0个点->通过第1、2个点:修正了“两对”这个情况的bug。
错误代码为
if(x.card[i]==2)//如果这张牌拥有两张
{
if(couple1==0)couple1=i;//如果之前没出现过对子
if(couple1)couple2=i;//之前出现过对子了,那这个就是第二个对子
}
写了两个if语句,问题在于两条语句的顺序错了。执行完第一句后,couple1已经被赋值了,第二句他必不可能为0,所以第二句也会被执行,从而couple2会变成和couple1一样的值。
正确代码应为
if(x.card[i]==2)//如果这张牌拥有两张
{
if(couple1==0)couple1=i;//如果之前没出现过对子
else couple2=i;//之前出现过对子了,那这个就是第二个对子
}
或者将两句顺序调换。
通过2个点->AC:修正了满堂红和三条的bug,我原先没判断三子的大小直接判断了后面剩余牌的大小,此块优先级应该为:先比较三子大小、后比较剩余两张牌的大小。
错误代码为
else if(three)//满堂红或三条
{
if(couple1){//有一个对子,满堂红 第5级
x.level=5.0;
x.level+=couple1*0.01;
}
else{//三条 第4级
x.level=4.0;
x.level+=single_value*0.01;
}
}
正确代码应为
else if(three)//满堂红或三条
{
if(couple1){//有一个对子,满堂红 第5级
x.level=5.0;
x.level+=three*0.01+couple1*0.0001;
}
else{//三条 第4级
x.level=4.0;
x.level+=three*0.01+single_value*0.0001;
}
}
希望能对大家有所帮助:)
完整代码:
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
struct People
{
string name;
string s;
int card[14];
double level;//大等级从1-8 细分等级顺序用小数点来算大小
}f[100005];
int trans(string str)
{
if(str=="A")return 1;
if(str=="2")return 2;
if(str=="3")return 3;
if(str=="4")return 4;
if(str=="5")return 5;
if(str=="6")return 6;
if(str=="7")return 7;
if(str=="8")return 8;
if(str=="9")return 9;
if(str=="10")return 10;
if(str=="J")return 11;
if(str=="Q")return 12;
if(str=="K")return 13;
}
int cmp(People a,People b)
{
if(a.level!=b.level)return a.level>b.level;
else return a.name<b.name;
}
void deal_the_level_of(People x,int cur)//current 当前的那个下标
{
int single_value=0;//剩下单张牌总值的和
int couple1=0,couple2=0;//有一个对子 、有两个对子 其值为对子对应的牌面
int three=0; //判断是否有三条
int four=0; //判断是否有四条
bool line=false;//判断是否有顺子 有的话更为true
int maxn;//顺子中最大的牌
for(int i=1;i<=13;i++)
{
if(x.card[i]==1)//遇到这张牌是单张的
{
int judge=1,j;//判断顺子
for(j=i+1;j<=i+4;j++)judge*=x.card[j];//不断相乘,只有全都是 1 ,乘出来才会为1.
if(judge==1){//是顺子
line=true;
maxn=j-1;
break;
}
else single_value+=i;
}
if(x.card[i]==2)//如果这张牌拥有两张
{
if(couple1==0)couple1=i;//如果之前没出现过对子
else couple2=i;//之前出现过对子了,那这个就是第二个对子
}
if(x.card[i]==3)three=i;//如果这张牌拥有三张
if(x.card[i]>=4)//这张牌拥有四张或五张,一样的都归为 四条 这个级别。
{
four=i;
if(x.card[i]==5)single_value+=i;//五张一样的 剩下那张归为单张
}
}
/*
注意!如果一个大等级中,有多个排序的优先级
那么:
第一优先级 乘 0.01
第二优先级 0.0001
第三优先级 0.000001
因为最大的单张牌面“K”的值为13,超过10了,如果少乘一个0会影响到大等级。
*/
if(x.card[10]*x.card[11]*x.card[12]*x.card[13]*x.card[1]==1)x.level+=8.0;//皇家同花顺 ,永远滴神!
else if(line)//顺子 第7级
{
x.level=7.0;
x.level+=maxn*0.01;
}
else if(four)//四条 第6级
{
x.level=6.0;
x.level+=four*0.01+single_value*0.0001;
}
else if(three)//满堂红或三条
{
if(couple1){//有一个对子,满堂红 第5级
x.level=5.0;
x.level+=three*0.01+couple1*0.0001;
}
else{//三条 第4级
x.level=4.0;
x.level+=three*0.01+single_value*0.0001;
}
}
else if(couple1)//两对或对子
{
if(couple2){//两对 第3级
x.level=3.0;
x.level+=couple2*0.01+couple1*0.0001+single_value*0.000001;
}
else{//单个对子 第2级
x.level=2.0;
x.level+=couple1*0.01+single_value*0.0001;
}
}
else {//高牌 最弱的第1级
x.level=1.0;
x.level+=single_value*0.0001;
}
f[cur]=x;//不用指针,将其转移给当前的这个f (因为f数组是全局变量) ,不然f数组的值不会改变的
}
int main()
{
int n,value;
string tmp;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>f[i].name>>f[i].s;
string str=f[i].s;
for(int j=0,t=0;t<5;t++)//共五张牌
{
if(str[j]!='1'){ //不为10
tmp=str[j]; //提取出这个字符
value=trans(tmp);//转换这个字符为对应的值
f[i].card[value]++;//该值的手牌数+1
j++;
}
else{ //遇到10了,只有 10 才会出现 1这个数字,因为牌值为1的是 A
f[i].card[10]++;
j+=2; //跳两格
}
}
deal_the_level_of(f[i],i);//处理f[i],记得带下标i
}
sort(f,f+n,cmp); //排序
for(int i=0;i<n;i++)cout<<f[i].name<<endl; //输出
return 0;
}
好难TOT
PTA-德州扑克 题解的更多相关文章
- 第一周PTA笔记 德州扑克题解
德州扑克 最近,阿夸迷于德州扑克.所以她找到了很多人和她一起玩.由于人数众多,阿夸必须更改游戏规则: 所有扑克牌均只看数字,不计花色. 每张卡的值为1.2.3.4.5.6.7.8.9.10.11.12 ...
- java和h5 canvas德州扑克开发中(二)
德州扑克网页源码在github上分享 https://github.com/lxr1907/pokers 感兴趣的可以上去看下. 1.通讯使用websocket,主要在message.js中. 2.用 ...
- java和h5 canvas德州扑克开发中(一)
先附上我的德州扑克测试地址 http://120.26.217.116:8080/LxrTexas/texasIndex.html 我和一个朋友的德州扑克历时一个多月开发,目前已经基本可玩. 前端主要 ...
- 德州扑克AI WEB版
继续之前的德州扑克话题,上次的DOS界面确实没法看,我女朋友说这是什么鬼.哈哈,估计只有自己能玩了 这两天重构了一下界面,基于web服务器和浏览器来交互. 服务器和客户端之间用websocket通信, ...
- 德州扑克AI实现 TexasHoldem Poker
参考了一下这篇文献,http://cowboyprogramming.com/2007/01/04/programming-poker-ai/ 自己用go实现了一个德州扑克AI,效果还可以. 正常和它 ...
- [swustoj 1088] 德州扑克
德州扑克(1088) 问题描述 德州扑克是一款风靡全球的扑克游戏.德州扑克一共有52张牌,没有王牌.每个玩家分两张牌作为“底牌”,五张由荷官陆续朝上发出的作为公共牌.开始的时候,每个玩家会有两张面朝下 ...
- 2015华为德州扑克入境摘要——软体project
直到6一个月2号下午12时00,华为长达一个月的德州扑克锦标赛落下帷幕也被认为是. 我们的团队一直共同拥有3民,间.一个同学(吴)负责算法设计,一个同学(宋)负责分析消息,而我负责的实现框架设计和详细 ...
- 德州扑克AI--Programming Poker AI(译)
前言: 最近在研究德州扑克的AI, 也想由浅入深的看下, 在网上找了一圈, 发现很多文章都提到了一篇文章: Programming Poker AI. 仔细拜读了一下, 觉得非常不错. 这里作下简单的 ...
- 德州扑克AI
德州扑克: 1:outs数,就是所听的牌的数量. 例子: 1:听顺子 4567 outs数就是8,能够成顺子的牌为3和8. 5689 outs数就是4,能够成顺子的牌只有7. 2:听同花 35 ...
随机推荐
- Java类的加载过程与ClassLoader的理解及测试
当程序准备运行某个类,但该类还未被加载到内存中时,会经过以下三个步骤进行类的加载: 类的加载(Load)→类的连接(Link)→类的初始化(Initialize) 加载:类经过javac.exe编译的 ...
- matplotlib如何画子图
目录 前言 常用的两种方式 方式一:通过plt的subplot 方式二:通过figure的add_subplot 方式三:通过plt的subplots 如何不规则划分 前言 Matplotlib的可以 ...
- ORB-SLAM2 论文&代码学习 —— 单目初始化
转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12358458.html 本文要点: ORB-SLAM2 单目初始化 ...
- JVM源码分析之临门一脚的OutOfMemoryError完全解读
概述 OutOfMemoryError,说的是java.lang.OutOfMemoryError,是JDK里自带的异常,顾名思义,说的就是内存溢出,当我们的系统内存严重不足的时候就会抛出这个异常(P ...
- 前端开发:这10个Chrome扩展你不得不知
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文出处:https://blog.bitsrc.io/10-top-chrome-extensions-f ...
- codewars--js--create phone number
Write a function that accepts an array of 10 integers (between 0 and 9), that returns a string of th ...
- clr via c# 程序集加载和反射(2)
查看,clr via c# 程序集加载和反射(1) 8,发现类型的成员: 字段,构造器,方法,属性,事件,嵌套类型都可以作为类型成员.其包含在抽象类MemberInfo中,封装了所有类型都有的一组属性 ...
- Golang中的Slice与数组
1.Golang中的数组 数组是一种具有固定长度的基本数据结构,在golang中与C语言一样数组一旦创建了它的长度就不允许改变,数组的空余位置用0填补,不允许数组越界. 数组的一些基本操作: 1.创建 ...
- Webpack实战(七):简单搞懂PostCSS的用法及与一些插件的用法
不知不觉地春节要来临了,今天已经是放假的第二天,想想回老家之后所有的时间就不是自己的了,要陪孩子玩,走亲戚等等,我还是趁着在郑州的这两天,把几天后春节要发布的文章给提前整整.在此,提前祝大家春节快乐! ...
- 共同战“疫”,CODING 帮助研发团队高效协同
新冠疫情下,家里蹲的日子继续延长.部分企业虽然受困于不能回公司办公,但都陆续开启了远程协作办公,远程协作领域被推上了风口.但「远程协同」看不见摸不着工作伙伴,个人的自律能力也无法保证,难免出现沟通响应 ...