程序设计思维与实践 week6 限时模拟——A - 掌握魔法の东东 II

东东决心提升牌技,面对AxB张独特扑克牌,需在移除两张后,从剩余牌中随机抽取三张形成一手牌。通过复杂算法评估不同牌型的可能性,包括同花顺、炸弹等,挑战在于数据存储、处理及结果判断。

A - 掌握魔法の东东 II

题目:
从瑞神家打牌回来后,东东痛定思痛,决定苦练牌技,终成赌神!
东东有 A × B 张扑克牌。每张扑克牌有一个大小(整数,记为a,范围区间是 0 到 A - 1)和一个花色(整数,记为b,范围区间是 0 到 B - 1。

扑克牌是互异的,也就是独一无二的,也就是说没有两张牌大小和花色都相同。

“一手牌”的意思是你手里有5张不同的牌,这 5 张牌没有谁在前谁在后的顺序之分,它们可以形成一个牌型。 我们定义了 9 种牌型,如下是 9 种牌型的规则,我们用“低序号优先”来匹配牌型,即这“一手牌”从上到下满足的第一个牌型规则就是它的“牌型编号”(一个整数,属于1到9):

同花顺: 同时满足规则 5 和规则 4.
炸弹 : 5张牌其中有4张牌的大小相等.
三带二 : 5张牌其中有3张牌的大小相等,且另外2张牌的大小也相等.
同花 : 5张牌都是相同花色的.
顺子 : 5张牌的大小形如 x, x + 1, x + 2, x + 3, x + 4
三条: 5张牌其中有3张牌的大小相等.
两对: 5张牌其中有2张牌的大小相等,且另外3张牌中2张牌的大小相等.
一对: 5张牌其中有2张牌的大小相等.
要不起: 这手牌不满足上述的牌型中任意一个.

现在, 东东从A × B 张扑克牌中拿走了 2 张牌!分别是 (a1, b1) 和 (a2, b2). (其中a表示大小,b表示花色)

现在要从剩下的扑克牌中再随机拿出 3 张!组成一手牌!!

其实东东除了会打代码,他业余还是一个魔法师,现在他要预言他的未来的可能性,即他将拿到的“一手牌”的可能性,我们用一个“牌型编号(一个整数,属于1到9)”来表示这手牌的牌型,那么他的未来有 9 种可能,但每种可能的方案数不一样。

现在,东东的阿戈摩托之眼没了,你需要帮他算一算 9 种牌型中,每种牌型的方案数。

Input:
第 1 行包含了整数 A 和 B (5 ≤ A ≤ 25, 1 ≤ B ≤ 4).
第 2 行包含了整数 a1, b1, a2, b2 (0 ≤ a1, a2 ≤ A - 1, 0 ≤ b1, b2 ≤ B - 1, (a1, b1) ≠ (a2, b2)).

Output:
输出一行,这行有 9 个整数,每个整数代表了 9 种牌型的方案数(按牌型编号从小到大的顺序)

Examples:

Input1:  
5 2
1 0 3 1
Output1:
0 0 0 0 8 0 12 36 0
 
Input2:
25 4
0 0 24 3
Output2:
0 2 18 0 0 644 1656 36432 113344

题目思路:

首先关注数据的储存,每张牌的属性有牌面大小和牌面花色两个属性,很自然的我们想到了使用一个结构体card来进行每张牌的储存。这道题是对于一系列的“一手牌”进行种类的判别,在每次判别时,我们需要对”一手牌“进行操作,”一手牌“等于五张牌,因此我们可以使用一个大小为5的card结构体数组进行一手牌的储存。结果是输出九种牌型的个数分别有多少,因此,我们可以使用一个大小为9的数组ans进行结果的储存。
其次,我们来关注每“一手牌”的形成,输入的A表示大小的范围,输入的B表示花色的范围,一共有A乘B张牌,很自然的可以想到,每张牌都可以看成一个大小为A乘B数组中的一个点,我们甚至还可以使用行主次序的方式来将每张牌与二维数组的位置进行映射,来进行每张牌的编号。输入的起始数据是固定的两张牌,为了形成“一手牌”,我们还需要三张牌,因此我们可以使用一个三重循环,来形成所有的“一手牌”,(注意遇到输入的两张牌时记得跳过,循环起始值也要注意),每次获取了“一手牌”,我们将这”一手牌“储存到结构体数组中,再对数组中的数据进行判别,判别出类别后,然后在ans中对应的某种类别的位置上使数值加一即可。
最后我们关注的问题是,如何对结构体数组中储存的一手牌进行类别的判断。首先,我们需要对这五张牌进行面值大小的排序,然后再进行后续的判别,因为我们已经对牌的面值大小进行了排序,所以每种类别的判别条件我们甚至都可以细致地列举出来:
1:同花:数组中的值的color属性全部相同。
2:顺子:数组中的值的nmb属性:[0]+1=[1], [1]+1=[2], [2]+1=[3], [3]+1=[4]。
3:同花顺:满足上述两者。
4:三代二:nmb属性:[0],[1],[2]相等且[3],[4]相等,或者[0],[1]相等且[2],[3],[4]相等.
5:炸弹:nmb属性:[0],[1],[2],[3]相等,或者[1],[2],[3],[4]相等。
6:三条:nmb属性:[0],[1],[2]相等,或者[1],[2],[3]相等,或者[2],[3],[4]相等。
7:两对:nmb属性:[0],[1]相等且[2],[3]相等,或者[0],[1]相等且[3],[4]相等,或者[1],[2]相等且[3],[4]相等。
8:一对:nmb属性:[0],[1]相等,或者[1],[2]相等,或者[2],[3]相等,或者[3],[4]相等。
9:要不起:不符合上述所有牌型。

代码实现

#include<iostream>
#include <algorithm> 
using namespace std; 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int A,B;//记录牌数,花色数 
int pai1,pai2;//记录初始两张牌的编号; 
int n;
int i,j,k,m;
int lable1, lable2;//记录是不是同化和顺子 

struct card
{
 int nmb;
 int color;
 bool operator < (const card &card1) const
 {
  return nmb < card1.nmb;
 }
};//定义结构体牌 

card pai[5];//储存一手牌;
int ans[9];//储存八种牌型数目

int main()
{
 scanf("%d %d",&A,&B);
 scanf("%d %d %d %d",&pai[0].nmb, &pai[0].color, &pai[1].nmb, &pai[1].color);
 pai1 = pai[0].nmb * B + pai[0].color;
 pai2 = pai[1].nmb * B + pai[1].color;//每张牌都类似于数组中的一个点,按照行主次序记录点的编号,先记录初始两点。 
 n = A * B;//记录牌的总数 

for(i=0; i<n; i++)
 {
  if(i == pai1 || i == pai2)//跳过已有的两张牌;
  {
   continue;
  }
  for(j = i+1; j<n; j++)
  {
   if(j == pai1 || j == pai2)
   {
    continue;
   }
   for(k = j+1; k<n; k++)
   {
    if(k == pai1 || k == pai2)
    {
     continue;
    }
    pai[0].nmb = pai1 / B;  pai[0].color = pai1 % B;
       pai[1].nmb = pai2 / B;  pai[1].color = pai2 % B;
       pai[2].nmb = i / B;  pai[2].color = i % B;
       pai[3].nmb = j / B;  pai[3].color = j % B;
       pai[4].nmb = k / B;  pai[4].color = k % B;//记录一手牌到数组中 
    
    sort(pai, pai+5);//将一手牌按照牌面大小排序方便后序操作
    lable1 = 0;lable2 = 0; 
    if(pai[0].color == pai[1].color && pai[1].color == pai[2].color && pai[2].color == pai[3].color && pai[3].color == pai[4].color)
    {
     lable1 = 1;
    }
    if(pai[0].nmb+1 == pai[1].nmb && pai[1].nmb+1 == pai[2].nmb && pai[2].nmb+1 == pai[3].nmb && pai[3].nmb+1 == pai[4].nmb)
    {
     lable2 = 1;
    }
    
    if(lable1 == 1 && lable2 == 1)
    {
     ans[0]++;
    }
    else if(lable1 == 1 && lable2 == 0)
    {
     ans[3]++;
    }
    else if(lable1 == 0 && lable2 == 1)
    {
     ans[4]++;
    }
    else if( (pai[0].nmb == pai[1].nmb && pai[1].nmb == pai[2].nmb && pai[2].nmb == pai[3].nmb) || (pai[1].nmb == pai[2].nmb && pai[2].nmb == pai[3].nmb && pai[3].nmb == pai[4].nmb) )
    {
     ans[1]++;
    }
    else if( (pai[0].nmb == pai[1].nmb && pai[2].nmb == pai[3].nmb && pai[3].nmb == pai[4].nmb) || ((pai[0].nmb == pai[1].nmb && pai[1].nmb == pai[2].nmb && pai[3].nmb == pai[4].nmb)))
    {
     ans[2]++;
    }
    else if((pai[0].nmb == pai[1].nmb && pai[1].nmb == pai[2].nmb) || (pai[1].nmb == pai[2].nmb && pai[2].nmb == pai[3].nmb) || (pai[2].nmb == pai[3].nmb && pai[3].nmb == pai[4].nmb))
    {
     ans[5]++;
    }
    else if((pai[0].nmb == pai[1].nmb && pai[2].nmb == pai[3].nmb) || (pai[0].nmb == pai[1].nmb && pai[3].nmb == pai[4].nmb) || (pai[1].nmb == pai[2].nmb && pai[3].nmb == pai[4].nmb))
    {
     ans[6]++;
    }
    else if(pai[0].nmb == pai[1].nmb || pai[1].nmb == pai[2].nmb || pai[2].nmb == pai[3].nmb || pai[3].nmb == pai[4].nmb)
    {
     ans[7]++;
    }
    else
    {
     ans[8]++;
       }
   }
  }
 } 
for(i=0; i<9; i++)
 {
  printf("%d ",ans[i]);
 }
 return 0;
}

心得体会:

其实这个题目的难度不是很大,也没有涉及到啥复杂的算法,但是比较麻烦,需要在做题的时候一步一步理清思路,从数据的储存,数据的处理,到结果的判断。每一步都应该想好如何实现,一步一步地来,否则会做着做着就思路混乱。我就是这样子的,在模拟的时候,没有做到一步一步地思考,想好了结果如何判别,但是倒过头来数据的储存处理又开始模糊混乱,发生了多次写了一大片又全部删掉的憨批操作,致使最后提交了一份超级长的代码,还wa了,事后经过认真思考,理清思路,细心的写好每一步,这道题还是很清晰的!

源码链接: https://pan.quark.cn/s/a4b39357ea24 斐讯K2是一款广受用户青睐的无线路由器,其运行表现稳定且具备较高的可操作性,在DIY爱好者群体中拥有极高的声誉。本资料将系统性地阐述斐讯K2的固件刷机方法及其关联的技术要点。固件升级是路由器爱好者改善设备性能、扩展功能的一种普遍手段,经由替换出厂固件,能够达成更加个性化的网络配置、增强安全防护等目标。斐讯K2固件资源库涵盖了多种知名的非官方固件,诸如Tomato Pheonix 不死鸟、高恪、PandoraBox 潘多拉等,这些固件均具备独特的优势,能够适配不同用户的需求。 1. Tomato Pheonix 不死鸟:Tomato是一款立足于Linux的开源固件,以其精巧、高效而备受推崇。不死鸟版本是专门为华硕及斐讯路由器优化的分支,提供了卓越的QoS(服务质量)配置、详尽的图表监控以及便捷的固件升级途径。对于那些需要精准调控带宽和监测网络状态的用户而言,这是一个理想的选项。 2. 高恪:高恪固件是OpenWrt的定制化版本,着重于操作的便捷性和运行的可靠性,特别适合对路由器操作不甚熟悉的用户群体。它提供了一些实用的功能,例如内置的广告屏蔽、快速测速工具等,同时保留了OpenWrt的适应性。 3. PandoraBox 潘多拉:潘多拉盒是另一款基于OpenWrt的固件,它以丰富的插件库和强大的自定义潜力而闻名。用户能够依据个人需求安装各类插件,实现更多功能,如远程接入、DDNS(动态域名解析服务)等。 4. 官方固件的纯净版本定制版本:官方固件通常更侧重于稳定性,纯净版意味着未预置额外的应用或服务,适合注重稳定性的用户。定制版则可能包含了制造商的特色功能或优...
源码下载地址: https://pan.quark.cn/s/926926948560 AS3.0XML结合的通用图片滚动功能,是一种基于ActionScript 3.0和XML技术的动态图像展示方案,非常适合初学者进行学习和实践应用。此项目的关键在于借助XML文件作为数据媒介,用来保存图像的相关参数,例如图像的链接地址、展示的次序等,接着在AS3.0环境中对XML进行解析,并动态地载入和展示这些图像,达成图像的滚动或是循环播放的目的。 我们需要明确ActionScript 3.0(AS3.0)是Adobe Flash Professional以及Flex Builder等开发工具中采用的编程语言,用于构建交互式内容以及丰富的互联网应用。相较于先前的版本,AS3.0在性能上有了大幅度的提升,并且引入了更为规范的面向对象编程模式,涵盖了类、接口以及包等概念。 XML(可扩展标记语言)是一种简明且高效的数据传输格式,既便于人类阅读和编写,也易于机器进行解析和生成。在该项目中,XML文件用于存储图像数据,例如图像的URL、延时的时长、动画的样式等,通过这种方式可以将数据程序代码分离,从而增强代码的可维护性可扩展程度。 实施这一图片滚动功能,主要涉及到以下AS3.0的核心知识点: 1. **XML解析**:运用`XML`类来载入并解析XML文件,从而获取图像的清单。AS3.0提供了简便的API来操作XML节点,例如`children()`、`attributes()`等,用以获取子节点和属性值。 2. **事件监听**:借助`EventDispatcher`类来监控载入和解析过程中的事件,比如`Event.OPEN`、`Event.PROGRESS`、`Event...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值