ZOJ 1111 - Poker Hands 解题报告

简介: Poker Hands (比较两手牌的大小)           http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=111           题目描述:这道题要求比较两手牌的大小。

          Poker Hands (比较两手牌的大小)

          http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=111

          题目描述:这道题要求比较两手牌的大小。每手牌都有5张牌组成,牌的大小的定义如下,首先确定这组牌的所属种类是下面哪一种(若同属同一种类,则根据该分类后面的比较规则继续比较,所属种类越靠后牌越大)。

          ● High Card:杂牌(不属于下面任何一种)。根据牌从大到小的顺序依次比较。

          ● Pair:有一对,加3张杂牌组成。先比较对的大小,再从大到小的顺序比较杂牌。

          ● Two Pairs:有两对,加1帐杂牌。先从大到小比较对的大小,再比较杂牌。

          ● Three of a Kind:有3张值相同的牌。比较这个值即可。

          ● Straingt:一条龙。即5张牌连续。比较最大的一张牌即可。

          ● Flush:清一色。即5张牌花色相同。和杂牌一样比较。

          ● Full House:3张值相同的牌,加上一对。比较三张相同的值即可。

          ● Four of a kind:有4张牌相同,即相当于一副“炸弹”。

          ● Straight flush:同花顺。即5张牌花色相同,并且连续。例如同花色的34567。

          题目输入多行,每一行含有10张牌,前五张属于Black,后五张属于White,每张牌由“牌值”字符和“花色”字符组成,注意10用大写字母T表示。牌从小到大的顺序是2,3,4,5,6,7,8,9,T,J,Q,K,A。要求输出比较结果。

          例如输入:

          2H 3D 5S 9C KD 2C 3H 4S 8C AH   (输出:White wins.)

          2H 4S 4C 2D 4H 2S 8S AS QS 3S   (输出:Black wins.)

          2H 3D 5S 9C KD 2C 3H 4S 8C KH  (输出:Black wins.)

          2H 3D 5S 9C KD 2D 3H 5C 9S KH  (输出:Ties.)

          ----------------------------------------------------------------------------------------

          分析:该题目还是属于一道简单题,我们只需要根据题目要求的比较规则去比较即可,我们假设一副牌所属的种类,用level值表示,level越大则牌越大。使用一个函数 int GetLevel(...) 来获取一副牌所属的种类。这里再判断牌的level之前,由于输入是乱序的,为了判别我们需要先把5张牌按从小到大的顺序排序。这里的排序只有5张牌,属于非常小规模的问题,因此我使用了交换数据成本最低的选择排序。同时,两幅牌的level如果相同,则我们还要具体根据牌的点数(value)做进一步判断,因此我们给GetLevel函数再传入一个int数组,把同level的继续比较的指标点数按顺序放入这个数组。这样,当level相同时,我们就继续从头查看order数组里的判别指标来继续判断。该题目的全部代码如下:

img_1c53668bcee393edac0d7b3b3daff1ae.gif img_405b18b4b6584ae338e0f6ecaf736533.gif ZOJ_1111_POKER_HANDS
/* ZOJ 1111 - Poker Hands
   其中选择排序代码引用自:<<C算法(第一卷 基础、数据结构、排序和搜索)(第三版)>>
 
*/
#include 
<stdio.h>
#include 
<string.h>

/*牌的定义*/
typedef 
struct tagCard
{
    
char name;  /*牌字符:2,3,, A*/
    
char value; /*牌字符在字符串中的索引*/
    
char suit;  /*花色*/    
} Card;

/*-----------排序相关-----------*/
typedef Card Item;

/*两副牌,每幅各有5张牌*/
Card cardsBlack[
5];
Card cardsWhite[
5];
/*用于在两副牌达到相同level时的辅助比较数组*/
int orderBlack[5];
int orderWhite[5];
/*读入的一行文本!*/
char line[32];


/*所有牌的值,其中10用T表示*/
char CardValues[]="23456789TJQKA";
/*判断t1-t2的差值,即两副牌差值*/
int lessthan(Item t1, Item t2)
{
    
return (t1.value<t2.value)? 1:0;    
}

/*return t1-t2*/
int diffence(Item t1, Item t2)
{
    
return (t1.value - t2.value);
}

/*交换a[]的i,j项*/
void exchange(Item a[], int i, int j)
{
    
char n1=a[i].name;
    
char v1=a[i].value;
    
char s1=a[i].suit;
    
    a[i].name
=a[j].name;
    a[i].value
=a[j].value;
    a[i].suit
=a[j].suit;
    
    a[j].name
=n1;
    a[j].value
=v1;
    a[j].suit
=s1;
}
 
 
/*选择排序*/
void SelectionSort(Item a[], int left, int right)
{
    
int i,j,min;
    
for(i=left; i<right; i++)
    {
        min
=i;
        
for(j=i+1; j<=right; j++)
            
if(lessthan(a[j],a[min])) min=j;
        exchange(a, i, min);
    }
}

/*---------------------排序相关的代码结束!----------------------*/

/*把读取的这一行输入给两副牌数组Black , White */
/*2H 3D 5S 9C KD 2C 3H 4S 8C AH*/
void InitCards()
{
    
int i;
    
for(i=0;i<5;i++)
    {
        cardsBlack[i].name
=line[3*i];
        cardsBlack[i].suit
=line[3*i+1];
        cardsBlack[i].value
=strchr(CardValues, cardsBlack[i].name)-CardValues;
        
        cardsWhite[i].name
=line[3*i+15];
        cardsWhite[i].suit
=line[3*i+16];
        cardsWhite[i].value
=strchr(CardValues, cardsWhite[i].name)-CardValues;
    }
}

/*把两副牌按照从小到大的顺序排好序*/
void SortCards()
{
    SelectionSort(cardsBlack, 
0, 4);
    SelectionSort(cardsWhite, 
0, 4);
}

/*判断从index起始的,向后数4张牌是否构成一副炸弹,即牌值相同!*/
int IsBomb(Item a[], int i)
{
    
if(  a[i+1].value==a[i].value
        
&& a[i+2].value==a[i].value
        
&& a[i+3].value==a[i].value)
         
return 1;
    
return 0;
}

/*是否三张相同*/
int IsThree(Item a[], int i)
{
    
if(  a[i+1].value==a[i].value
        
&& a[i+2].value==a[i].value)
        
return 1;
    
return 0;
}

/*是否两张相同的对*/
int IsPair(Item a[], int i)
{
    
if(a[i+1].value==a[i].value)
        
return 1;
    
return 0;
}

/*是否5张牌的牌值连续*/
int IsStraight(Item a[])
{
    
if(  (a[1].value-a[0].value)==1
        
&& (a[2].value-a[1].value)==1
        
&& (a[3].value-a[2].value)==1
        
&& (a[4].value-a[3].value)==1 )
        
return 1;
    
return 0;
}

/*是否5张牌都是同花色*/
int IsFlush(Item a[])
{
    
if(  a[1].suit==a[0].suit 
        
&& a[2].suit==a[0].suit
        
&& a[3].suit==a[0].suit
        
&& a[4].suit==a[0].suit)
        
return 1;
    
return 0;
}

/*得到某副已经排好序的牌等级(同花顺最高!,杂牌最低)*/
/*order是等级相同时的辅助比较值*/
int GetLevel(Item a[], int order[])
{
    
int level,i,t1,t2,t3;
    order[
0]=order[1]=order[2]=order[3]=order[4]=0;
    
    
/*=============level 9 - Straight flush. 同花顺,花色相同,并且牌连续==================*/
    level
=9;
    
if(IsStraight(a) && IsFlush(a))
    {
        order[
0]=a[4].value;/*Ranked by the highest card in the hand. */
        
return level;
    }
    
    
/*==============level 8 - Four of a kind. 有4相同值的牌,即一副炸弹 ===================*/
    level
--;
    
if(IsBomb(a, 0) || IsBomb(a, 1))
    {
        
/*注意如果有4张相同的牌,则a[1]一定位于这4帐牌之中!!!*/
        order[
0]=a[1].value;/*Ranked by the value of the 4 cards.*/
        
return level;
    }
    
    
/*==============level 7 - Full House. 有3张牌是相同值,另外2张牌也是相同值,OOOXX, XXOOO*/
    level
--;
    
if( (IsThree(a,0) && IsPair(a,3)) || (IsThree(a, 2) && IsPair(a, 0)) )
    {
        
/*XXXOO*//*Ranked by the value of the 3 cards. */
        order[
0]=a[2].value;
        
return level;
    }
    
    
/*===============level 6 - Flush. 5张牌同花色================================*/
    level
--;
    
if(IsFlush(a))
    {
        
/*If the highest cards have the same value, the hands are ranked by the next highest*/
        
/*order中是从大到小排列的牌值,用于判别大小*/
        
for(i=0;i<5;i++) order[i]=a[4-i].value;
        
return level;
    }
    
    
/*================level 5 - Straight. 一条龙,即5张牌的值连续.====================*/
    level
--;
    
if(IsStraight(a))
    {
        order[
0]=a[4].value;/*ranked by their highest card. */
        
return level;
    }
    
    
/*================level 4 - Three of a Kind. 有三张相同值。OOOXY,XOOOY,XYOOO,=====*/
    level
--;
    
if(IsThree(a,0) || IsThree(a,1) || IsThree(a,2))
    {
        order[
0]=a[2].value;/*ranked by the value of the 3 cards. */
        
return level;
    }
    
    
/*================level 3 - Two Pairs. 两副对,另一个杂牌的索引用i来记录.============*/
    level
--;
    
if(  (i=0, IsPair(a,1) && IsPair(a,3))         /*-OOII*/
        
|| (i=2, IsPair(a,0) && IsPair(a,3))        /*OO-II*/
        
|| (i=4, IsPair(a,0) && IsPair(a,2)) )    /*OOII-*/
    {
        order[
0]=a[3].value;/*I: max pair's value;*/
        order[
1]=a[1].value;/*O: min pair's value;*/
        order[
2]=a[i].value;/*-: remaining card;  */
        
return level;
    }
    
    
/*================level 2 - Pair. 一副对;OOxyz, xOOyz, xyOOz, xyzOO.============*/
    
/*i存储Pair的位置,t1,t2,t3存储其他值的位置 */
    level
--;
    
if(  (i=0, t1=4, t2=3, t3=2, IsPair(a,0))        /*OOxyz*/
        
|| (i=1, t1=4, t2=3, t3=0, IsPair(a,1))        /*xOOyz*/
        
|| (i=2, t1=4, t2=1, t3=0, IsPair(a,2))        /*xyOOz*/
        
|| (i=3, t1=2, t2=1, t3=0, IsPair(a,3)) )    /*xyzOO*/
    {
        
/*ranked by the value of the cards forming the pair. 
          If these values are the same, the hands are ranked 
          by the values of the cards not forming the pair, 
          in decreasing order. 
*/
        order[
0]=a[i].value;
        order[
1]=a[t1].value;
        order[
2]=a[t2].value;
        order[
3]=a[t3].value;
        
return level;
    }
    
    
/*=================level 1 - High Card. 完全的杂牌。不构成上诉任何情况,从大到小比=====*/
    level
--;
    
for(i=0;i<5;i++) order[i]=a[4-i].value;
    
return level;
}

int main()
{
    
int levelBlack, levelWhite, i;
    
while(gets(line)!=NULL && strlen(line)>2)
    {
        InitCards();    
/*把读入的字符串设置到数组中*/
        SortCards();            
/*把两副牌都排好序*/
        levelBlack
=GetLevel(cardsBlack, orderBlack);
        levelWhite
=GetLevel(cardsWhite, orderWhite);
        
        
/*比较两副牌*/
        
if(levelBlack > levelWhite)
            printf(
"Black wins.\n");
        
else if(levelBlack < levelWhite)
            printf(
"White wins.\n");
        
else
        {
            
/*级别相同,需要比较order数组*/
            
for(i=0;i<5;i++)
            {
                
if(orderBlack[i]>orderWhite[i])
                {
                    printf(
"Black wins.\n");
                    
break;/*已经比较出结果!*/
                }
                
else if(orderBlack[i]<orderWhite[i])
                {
                    printf(
"White wins.\n");
                    
break;
                }
            }
            
/*依然未分出胜负,则平局!*/
            
if(i==5) printf("Tie.\n");
        }
    }
    
return 0;
}

          C代码在ZOJ上的典型内存是160K,因此该代码在AC后顺利跻身解排行榜的第一位。虽然这个题目比较简单,在我看到这个题目的时候就有了AC的把握。代码也很快写好了,然而此后的过程却使得该题成为我AC的最坎坷的题目之一,非常痛苦,在我信心满满确认无误的提交后,却发现每次都是的Segment Fault错误,在无数次调节输入和数组长度后都无法解决该问题,导致我百思不得其解!仔细检查也发现不了任何有野指针或者越界之类的错误。灰心失望之际我把代码拷贝到VC6里面编译,结果VC6的一个警告马上让我发现了问题所在:

          原来问题出在我无论如何也不会怀疑的核心判别函数上,即GetLevel函数里的一个判别:

          在给t1,t2,t3赋值时,我把t1=.., t2=.., t3=..,粗心的写作了t1=.., t2=.., t1=..; 导致t3是一个不确定值,从而使后续的代码发生了越界!汗!而在TC2.0中却没有给出任何警告! 再改正这个问题以后顺利AC。

目录
相关文章
|
9天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
7684 13
|
7天前
|
人工智能 测试技术 API
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
Jev是TypeSafe AI推出的“系统一模型”,不生成文本,专做毫秒级结构化决策:Choice(多选)、Score(打分)、Noul(是非概率)。响应快193倍、成本低444倍,适合工单路由、内容审核、测试定级等高频判断场景。
1642 4
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
|
4天前
|
人工智能 JavaScript 芯片
DeepSeek 官方偷偷上传 Harness 桌面端安装包,我已经用上了。。附最新下载地址
DeepSeek Harness 官方的桌面端安装包被网友扒出来了,2 分钟讲明白如何使用,体验如何,适合作为 AI 编程工具么?附最新 Windows 和 Mac 双端的下载地址
1407 1
|
8天前
|
人工智能 并行计算 PyTorch
秋叶 ComfyUI 2026 整合包 v3.2 完整部署教程:Python 3.13 + Torch 2.13 全栈升级
秋叶aaaki ComfyUI 2026年8月整合包v3.2正式发布!全面升级Python 3.13.11、PyTorch 2.13.0+cu130及ComfyUI v0.30.2,原生支持MiniMax H3、Wan 2.2、Qwen-Image-2.1等2026主流音视频/图像模型,解压即用,无需环境配置。
1187 9
|
21天前
|
人工智能 自然语言处理 安全
阿里云千问办公 QwenWork详细介绍:产品核心能力、典型场景、价格及常见问题解答
千问办公是阿里云推出的一站式AI办公平台,主打"不止于对话,更注重交付",依托通义千问旗舰大模型,用户一句话即可完成数据分析、PPT生成、视频剪辑等复杂任务,直接输出可用成果。产品深度打通钉钉生态与企业OA,覆盖桌面端、网页端,提供企业标准版198元/人/月等多档订阅方案,新用户注册即赠2000积分,适配工程师、HR、财务等多职业办公场景,成为能动手干活的"全能AI同事"。
3670 10
|
5天前
|
编解码 缓存 PyTorch
16G 显卡能跑 Qwen-Image 2.1 吗?
9月20日,阿里Qwen开源Qwen-Image-2.1:7B DiT图像模型+8B文本编码器+VAE,单模型支持文生图与图像编辑,原生输出2K PNG(含Alpha通道),支持10张参考图。在自建Qwen-Image-Bench达60.28分(开源模型第一),GenAI Showdown文生图排名7/15。16G显存可跑1024×1024(需INT8量化+ComfyUI优化),但2K需24G以上。注意其Qwen Research License限非商业用途。
609 1
|
6天前
|
人工智能 编解码 并行计算
MiniMax-H3 一键整合包技术文档:8G 显存运行 AI 漫剧制作 —— 角色替换 / 动作迁移 / 文图生视频部署与调参指南
MiniMax H3 是 MiniMax 开源的全模态视频生成模型,支持文/图/音/视多条件输入,输出最高2K、15秒带双声道音频视频。本文档详述其Int8量化版在8GB显存下的本地一键部署、三段式工作流(EDIT/REPLACE/CONTINUE)、参数调优及常见问题排查。(239字)
|
16天前
|
缓存 IDE Java
【保姆级】Android Studio下载、安装和汉化教程(2026最新)
Android Studio 是 Google 官方推出的免费 Android 应用开发集成环境,基于 IntelliJ IDEA,内置模拟器、调试器、性能分析及 Compose 界面工具,功能全面,文档丰富,是安卓开发首选工具。(239字)
1720 1

热门文章

最新文章