扑克牌牌型 问题描述 有 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 种牌型每种牌型的方案数。
第 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 ; 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 ]++; return ; } else if (sameC == 3 && diffC == 1 ) { if (diffPos == 0 || diffPos == 3 ) pK[1 ]++; if (diffPos == 1 || diffPos == 2 ) pK[2 ]++; return ; } else if (colorS == true && Shunza == false ) { pK[3 ]++; return ; } else if (colorS == false && Shunza == true ) { pK[4 ]++; 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 ]++; if (same3 == false ) pK[6 ]++; return ; } else if (sameC == 1 && diffC == 3 ) { pK[7 ]++; return ; } else pK[8 ]++; } 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 ; }