题目描述
小明被劫持到X赌城,被迫与其他3人玩牌。
一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。
这时,小明脑子里突然冒出一个问题:
如果不考虑花色,只考虑点数,也不考虑自己得到的牌的先后顺序,自己手里能拿到的初始牌型组合一共有多少种呢?
注意
我们将牌从1到13编号,每种编号的牌有四张。
一个是牌不考虑花色只考虑点数,也就是说每种编号的四张牌认为是一样的。
一个是不考虑得到的牌的先后顺序,如1 1 1 1 2 2 2 2 3 3 3 3 4这13张牌和2 2 2 2 1 1 1 1 3 3 3 3 4这十三张牌只能算一种。
那么就不能用如下的dfs,这会导致刚刚列举的两种情况重复计数。
static int[] vis = new int[14]; //编号为i的牌取了几张
static int ans = 0; //排列种数
static void dfs(int k) { // k为考虑到第几张牌
if (k == 14) {
ans++;
}
for (int i = 1; i < 14; i++) {
// 编号为i的牌已经选完了
if (vis[i] == 4) {
continue;
}
vis[i]++;
dfs(k + 1);
vis[i]--;
}
}
java代码1
应该考虑的是将13张牌从1到13编号,对于每一个数值的牌都有选择0,1,2,3,4种选法,直到处理完了所有的牌,如果选的牌数为13则answer++。
import java.util.*;
public class Main {
static int ans = 0;
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
dfs(1, 0);
System.out.println(ans);
sc.close();
}
/**
* 深度优先搜索求牌组合法
*
* @param k
* 当前考虑到编号为k的牌,该牌可能选择0~4张
* @param num
* 截止目前为止已经选了多少张牌
*/
static void dfs(int k, int num) {
// 处理完了编号从1到13的牌,考虑已经选的牌数是不是为13,是的话则ans++
if (k == 14) {
if (num == 13) {
ans++;
}
return;
}
// 选的牌数大于13,剪枝
if (num > 13) {
return;
}
// 对于编号为k的牌,可以选择0~4张
// 选择i张编号为k的牌,递归处理编号为k+1的牌
for (int i = 0; i < 5; i++) {
dfs(k + 1, num + i);
}
}
}
java代码2
暴力大法好啊
对于每个编号的牌都可能选择0,1,2,3,4张,那么遍历所有的牌,如果最终选择的牌数为13则answer++。
当然该代码可以改进,比如当在某一个for循环中直接计算到目前为止选了多少张牌,要是大于13直接剪枝。
import java.util.*;
public class Main {
static int ans = 0;
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
for (int a = 0; a <= 4; a++)
for (int b = 0; b <= 4; b++)
for (int c = 0; c <= 4; c++)
for (int d = 0; d <= 4; d++)
for (int e = 0; e <= 4; e++)
for (int f = 0; f <= 4; f++)
for (int g = 0; g <= 4; g++)
for (int h = 0; h <= 4; h++)
for (int i = 0; i <= 4; i++)
for (int j = 0; j <= 4; j++)
for (int k = 0; k <= 4; k++)
for (int l = 0; l <= 4; l++)
for (int m = 0; m <= 4; m++) {
if (a + b + c + d + e + f + g + h + i + j + k + l + m == 13)
ans++;
}
System.out.println(ans);
sc.close();
}
}