程序设计思维Week6-限时模拟
掌握魔法の东东II
Description
东东有 A × B 张扑克牌。每张扑克牌有一个大小(整数,记为a,范围区间是 0 到 A - 1)和一个花色(整数,记为b,范围区间是 0 到 B - 1。
扑克牌是互异的,也就是独一无二的,也就是说没有两张牌大小和花色都相同。
“一手牌”的意思是你手里有5张不同的牌,这 5 张牌没有谁在前谁在后的顺序之分,它们可以形成一个牌型。 我们定义了 9 种牌型,如下是 9 种牌型的规则,我们用“低序号优先”来匹配牌型,即这“一手牌”从上到下满足的第一个牌型规则就是它的“牌型编号”(一个整数,属于1到9):
1.同花顺: 同时满足规则 2 和规则 3.
2.顺子 : 5张牌的大小形如 x, x + 1, x + 2, x + 3, x + 4
3.同花 : 5张牌都是相同花色的.
4.炸弹 : 5张牌其中有4张牌的大小相等.
5.三带二 : 5张牌其中有3张牌的大小相等,且另外2张牌的大小也相等.
6.两对: 5张牌其中有2张牌的大小相等,且另外3张牌中2张牌的大小相等.
7.三条: 5张牌其中有3张牌的大小相等.
8.一对: 5张牌其中有2张牌的大小相等.
9.要不起: 这手牌不满足上述的牌型中任意一个.
现在, 东东从A × B 张扑克牌中拿走了 2 张牌!分别是 (a1, b1) 和 (a2, b2). (其中a表示大小,b表示花色)
现在要从剩下的扑克牌中再随机拿出 3 张!组成一手牌!!
其实东东除了会打代码,他业余还是一个魔法师,现在他要预言他的未来的可能性,即他将拿到的“一手牌”的可能性,我们用一个“牌型编号(一个整数,属于1到9)”来表示这手牌的牌型,那么他的未来有 9 种可能,但每种可能的方案数不一样。
需要帮他算一算 9 种牌型中,每种牌型的方案数。
输入A和B,以及拿走的两张牌a1,b1,a2,b2
输出每种牌型的方案数。
Sample
Input
5 2
1 0 3 1
Output
0 8 0 0 0 12 0 36 0
Input
25 4
0 0 24 3
Output
0 0 0 2 18 1656 644 36432 113344
Idea
首先我们知道了牌堆中牌的大小范围和花色范围以及在手中的两张牌,就可以初始化牌堆,牌堆中还有AxB-2张牌。接下来我们就从牌堆中选出三张牌,利用三重循环形成不同的组合并保证这三张牌中没有相同的牌。对于每种组合,加上手上的两张牌,就可以形成一种牌型,我们用封装的judge函数判断当前这5张牌是什么牌型。
牌型判断:
①同花顺是第二、第三种情况的同时达成。
②顺子:对5张牌的大小升序排序,当从小到大每张牌递增1时,就符合
③同花:5张牌的花色值都相等。
④-⑨放在一起判断,我们用m数组记录5张牌出现过的不同的大小,以及用n数组每个大小对应的出现次数,通过对5张牌依次与m比较,最终可以获得出现过k个不同的大小,把n降序排序就可以获得出现次数最多的大小的次数max1。依据不同的k和max1,可以判断牌型。
最终输出每种牌型的方案数。
Summary
这道题条件比较多,要先分解题意,化成几个子问题。
①首先解决判断牌型的问题,对④-⑨可以放在一起判断。
②选择剩下的三张牌,一开始我以为用DFS进行类似迷宫的搜索,后来发现其实不然,5张牌大概率是在二维数组中不相连的,不应该用DFS扩展。所以我们可以先确定牌堆里还剩下的牌,再用个三重循环选择第三、第四、第五张牌。
要注意5张牌里不能有相同的牌,初始化牌堆时也要去掉手里已有的两张牌。
Codes
#include<iostream>
#include<algorithm>
using namespace std;
struct cards
{
int a;
int b;
};
cards c[5];
cards tot[120];
int num[10] = { 0 };
int A, B;
bool cmp(int a, int b) {
return a > b;
}
bool type2() {
int m[5];
for (int i = 0; i < 5; i++)
m[i] = c[i].a;
sort(m, m + 5);
return (m[0] + 1 == m[1]) && (m[1] + 1 == m[2]) && (m[2] + 1 == m[3]) && (m[3] + 1 == m[4]);
}
bool type3() {
return c[0].b == c[1].b&&c[2].b == c[1].b&&c[2].b == c[3].b&&c[3].b == c[4].b;
}
void judge(){
if (type2() && type3()) { num[1]++; }
else if (type2()) { num[2]++; }
else if (type3())num[3]++;
else {
int m[5];
int n[5];
memset(m, -1, sizeof(m));
memset(n, 0, sizeof(n));
int k = 1;
m[0] = c[0].a;
n[0]++;
for (int i = 1; i < 5; i++) {
for (int j = 0; j < k; j++) {
if (c[i].a == m[j]) {
n[j]++; break;
}
if (j == k-1) { m[k] = c[i].a; k++; }
}
}
sort(n, n + k, cmp);
int max1 = n[0];
if (k == 2 && max1 == 4) { num[4]++; }
else if (k == 2 && max1 == 3)num[5]++;
else if (k == 3 && max1 == 2)num[6]++;
else if (k == 3 && max1 == 3)num[7]++;
else if (k == 4 && max1 == 2) { num[8]++; }
else if (k == 5)num[9]++;
}
}
int main()
{
cin.sync_with_stdio(false);
cin >> A >> B;
cin >> c[0].a >> c[0].b;
cin >> c[1].a >> c[1].b;
//初始化牌堆
int n = 0;
for (int i = 0; i < A; i++)
{
for (int j = 0; j < B; j++)
{
if ((i == c[0].a && j == c[0].b) || (i == c[1].a && j == c[1].b))
{
continue;
}
else
{
tot[n].a = i;
tot[n].b = j;
n++;
}
}
}
//在牌堆选剩下三张牌
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
for (int t = j + 1; t < n; t++)
{
if (i == j || i == t || j == t)
{
continue;
}
else
{
c[2] = tot[i];
c[3] = tot[j];
c[4] = tot[t];
judge();
}
}
for (int i = 1; i <=9; i++)
printf("%d ", num[i]);
}