0%

扑克牌牌型

扑克牌牌型

问题描述

有 A × B 张扑克牌。每张扑克牌有一个大小(整数,记为a,范围区间是 0 到 A - 1)和一个花色(整数,记为b,范围区间是 0 到 B - 1。
扑克牌是互异的,也就是独一无二的,也就是说没有两张牌大小和花色都相同。
“一手牌”的意思是你手里有5张不同的牌,这 5 张牌没有谁在前谁在后的顺序之分,它们可以形成一个牌型。 我们定义了 9 种牌型,如下是 9 种牌型的规则,我们用“低序号优先”来匹配牌型,即这“一手牌”从上到下满足的第一个牌型规则就是它的“牌型编号”(一个整数,属于1到9):
1. 同花顺: 同时满足规则 5 和规则 4.
2. 炸弹 : 5张牌其中有4张牌的大小相等.
3. 三带二 : 5张牌其中有3张牌的大小相等,且另外2张牌的大小也相等.
4. 同花 : 5张牌都是相同花色的.
5. 顺子 : 5张牌的大小形如 x, x + 1, x + 2, x + 3, x + 4
6. 三条: 5张牌其中有3张牌的大小相等.
7. 两对: 5张牌其中有2张牌的大小相等,且另外3张牌中2张牌的大小相等.
8. 一对: 5张牌其中有2张牌的大小相等.
9. 要不起: 这手牌不满足上述的牌型中任意一个.
现在从A × B 张扑克牌中拿走 2 张牌,分别是 (a1, b1) 和 (a2, b2). (其中a表示大小,b表示花色),现在要从剩下的扑克牌中再随机拿出 3 张,组成一手牌。
求在所有可能的方案中,这 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 种牌型的方案数(按牌型编号从小到大的顺序)

Sample

Input: 
5 2
1 0 3 1

Output:
0 0 0 0 8 0 12 36 0

Input:
25 4
0 0 24 3

Output:
0 2 18 0 0 644 1656 36432 113344

Limitation

Time limit		2000 ms
Memory limit 524288 kB

解题思路

这是一道搜索问题,暴力for循环搜索就能解决,不需要用到排列组合……

本题主要有两步:求出所有组合,判断属于哪种牌型。

求组合

本来是采用递归求出所有组合的,但是扑克牌有点数和花色,二维数组的组合枚举不会写……由于每一张牌都不同,所以把二维数组变成一维数组进行枚举,然后……不知怎么样反正就是WA了,判断牌型没出问题,但是找不出组合哪里出问题,纠结半天,也还是找不出来……后来看见某人发了说说才恍然大悟——这是一个搜索问题!😕

看数据比较小,25×4,多重for循环应该不会超时,所以后来直接暴力for循环求组合,但是又出现了新问题:

for (int i = 0; i != a; i++)
for (int j = 0; j != b; j++)
if (!(i == a1 && j == b1) && !(i == a2 && j == b2))
for (int ii = i; ii != a; ii++)
for (int jj = 0; jj != b; jj++)
if (!(ii == a1 && jj == b1) && !(ii == a2 && jj == b2) &&
!(ii == i && jj == j))
for (int iii = ii; iii != a; iii++)
for (int jjj = jj; jjj != b; jjj++)
if (!(iii == a1 && jjj == b1) &&
!(iii == a2 && jjj == b2) &&
!(iii == i && jjj == j) &&
!(iii == ii && jjj == jj)) {
poke p1(i, j);
pv.push_back(p1);
poke p2(ii, jj);
pv.push_back(p2);
poke p3(iii, jjj);
pv.push_back(p3);
sort(pv.begin(), pv.end(), cmp);
pokeKind(pv);
}

第二&第三大次的for循环无法保证选的牌这一次和下一次选的不是相反的,比如第n次选牌,第二大次for循环选了红桃4,第三大次for循环选了黑桃4;然而第n+1次选牌,第二大次for循环选了黑桃4,第三大次for循环选了红桃4……

我的改进就是每2个小次的for循环合并,手牌标号%总点数 = 当前点数手牌标号/总点数= 当前花色,比如手牌(点数, 花色): (0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), ..., (4, 0), (4, 1)标号就是0, 1, 2, 3, 4, 5, ..., 8, 9

排序后判断牌型

我用了5个变量:int sameC, diffC:几组两两连续的点数相同/不同;bool colorS, Shunza:是否同花/顺子;int diffPos:最后一次出现连续两两不等的位置。

具体见pokeKind()函数区分。

收获

有时暴力一下可能出奇迹……

源代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

struct poke {
int point;
int color;
poke(int p, int c) :point(p), color(c) { }
bool operator <(const poke p)const {
if (p.point == point)
return color < p.color;
return point < p.point;
}
};

int pK[9];

bool cmp(poke a, poke b) {
return a < b;
}

void pokeKind(vector<poke> v) {
int sameC = 0, diffC = 0; //4=; 3=&2=; 3=; 2=&2=; 2=
int diffPos = 0;
bool colorS = true;//同花
bool Shunza = true;//顺子
for (int i = 0; i != v.size() - 1; i++) {
if (v[i].point == v[i + 1].point)
sameC++;
if (v[i].point != v[i + 1].point) {
diffC++;
diffPos = i;
}
if (colorS == true && v[i].color != v[i + 1].color)
colorS = false;
if (Shunza == true && v[i].point + 1 != v[i + 1].point)
Shunza = false;
}
if (colorS == true && Shunza == true) {
pK[0]++;//1 同花顺
return;
}

else if (sameC == 3 && diffC == 1) {
if (diffPos == 0 || diffPos == 3)
pK[1]++;//2 炸弹
if (diffPos == 1 || diffPos == 2)
pK[2]++;//3 三带二
return;
}
else if (colorS == true && Shunza == false) {
pK[3]++;//4 同花
return;
}

else if (colorS == false && Shunza == true) {
pK[4]++;//5 顺子
return;
}

else if (sameC == 2 && diffC == 2) {
bool same3 = false;
for(int i=0;i!=v.size()-2;i++)
if (v[i].point == v[i + 2].point)
same3 = true;
if (same3 == true)
pK[5]++;//6 三条
if (same3 == false)
pK[6]++;//7 两对
return;
}
else if (sameC == 1 && diffC == 3) {
pK[7]++;//8 一对
return;
}
else
pK[8]++;//9 要不起
}

int main() {
int a, b;
cin >> a >> b;

int a1, b1, a2, b2;
cin >> a1 >> b1 >> a2 >> b2;

for (int i = 0; i < 9; i++)
pK[i] = 0;

for (int i = 0; i != a * b - 2; i++) {
int ai = i % a, bi = i / a;
if (!(ai == a1 && bi == b1) && !(ai == a2 && bi == b2)) {
for (int j = i + 1; j != a * b - 1; j++) {
int aj = j % a, bj = j / a;
if (!(aj == a1 && bj == b1) && !(aj == a2 && bj == b2)) {
for (int k = j + 1; k != a * b; k++) {
int ak = k % a, bk = k / a;
if (!(ak == a1 && bk == b1) && !(ak == a2 && bk == b2)) {
poke o1(a1, b1);
poke o2(a2, b2);
vector<poke> pv;
pv.push_back(o1);
pv.push_back(o2);

poke p1(ai, bi);
pv.push_back(p1);
poke p2(aj, bj);
pv.push_back(p2);
poke p3(ak, bk);
pv.push_back(p3);
sort(pv.begin(), pv.end(), cmp);
pokeKind(pv);
}
}
}
}
}
}

for (int i = 0; i < 9; i++)
cout << pK[i] << " ";
cout << endl;

return 0;
}