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了,事后经过认真思考,理清思路,细心的写好每一步,这道题还是很清晰的!