于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

最新文章

  1. wpf 加载项目图片的几种写法
  2. 讲讲Android事件拦截机制
  3. java12
  4. debain 8为Iceweasel安装flash播放器
  5. 简单的androidStudio 添加Jar包
  6. 记一次ORACLE的UNDO表空间爆满分析过程
  7. (原创)mybatis学习四,利用mybatis自动创建代码
  8. PHP之:随机抽取一个数&amp;&amp;随机函数
  9. 旨在脱离后端环境的前端开发套件 - IDT Server篇
  10. android的R.java
  11. YYCache 源码分析(一)
  12. hadoop+hive+spark搭建(一)
  13. ceres-solver库使用示例
  14. css中固定宽高div与不固定宽高div垂直居中的处理办法
  15. Deepin或者Ubuntu上永久配件navicat
  16. HDU5470 Typewriter SAM 动态规划 单调队列
  17. Jersey RESTful WebService框架学习(三)使用@QueryParam
  18. Beautiful Soup (一)
  19. 如何将Mac系统OS X Yosemite装到外部磁盘?(转)
  20. WP8.1学习系列(第十八章)——Windows Phone 交互和可用性

热门文章

  1. ORB-SLAM2 论文&amp;代码学习 —— 概览
  2. 协程的原理(Coroutine Theory)
  3. H5监听浏览器滚动条scrollbar
  4. 1Python学习CentOS 7 Linux环境搭建
  5. Python3标准库:weakref对象的非永久引用
  6. 使用MuMu模拟器调试AndroidStudio项目
  7. 2、CentOS7密码重置
  8. 转载:字符编码简介 ASCII UTF-8 ISO8859-1
  9. 回炉重造之重读Windows核心编程-004-进程
  10. centos的安装与配置,Linux下基本命令、权限控制,解压缩文件以及软件的安装与卸载