链接:https://ac.nowcoder.com/acm/contest/3036/G
来源:牛客网
这次是一个成年男性,他正在玩弄着手上的扑克牌,纸牌在他手中翻飞着,如同空中飞舞的蝴蝶。
「死后居然被计入英灵座,现在居然还被召唤到这里,真是很奇妙啊」他先发言了「我并无任何武艺,但对数学方面略有心得,我即为七骑之中的魔术师(caster)」
「呜」他所说的信息实在太少太少了,我根本没法判别他的真名
「你们能到达这里必是多少有些许智慧的」他直接把17张扑克牌飞了过来。扑克牌如同利刃一般飞来,但并没有故意瞄准我,这也叫没有什么武艺么
「我对赌博很有兴趣,但是这纸牌游戏也只是无趣的记忆游戏。捡起这些纸牌吧。」他从牌堆里面也抽出了17张牌「和我玩一场游戏,赢了就可以过去,输了就永远在这复数的空间里徘徊」
(规则与实际斗地主有出入,请以本题题面为准)
给出17张牌,计算刚开局总共有多少种不同的出牌方案。
牌的种类,顺序(从小到大):
3 4 5 6 7 8 9 0(代表10) J Q K A 2
出牌方式:
单个牌:单张牌,比如:3
对子:两张种类相同的牌,比如:2,2
炸弹:四张种类相同的牌,比如:6,6,6,6
三带一:有两种牌,一种牌有三张,另一种牌有一张,比如:3,3,3,A
三带二:有两种牌,一种牌有三张,另一种牌有两张,比如:3,3,3,A,A
五单顺子:五张连续的单牌,且五张牌种类各不相同。比如:4,5,6,7,8。五单顺子的牌的种类可以包括 2,比如:J,Q,K,A,2,也是五单顺子。注意:A,2,3,4,5,不是五单顺子,3,4,5,6,6,也不是五单顺子
由于花色的原因,即使是相同种类的牌,也是不同的牌
第一行一个整数T(1 ≤ T ≤ 100),代表T组样例,
对于每组样例,输入一行,每行输入一个仅由{‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, ‘0’, ‘J’, ‘Q’, ‘K’, ‘A’, ‘2’}字符组成的字符串str,(|str|==17)。其中|str|代表字符串的长度。
题目保证每种牌最多四张(代表四种花色)
输出描述:对于每一行输入,输出有多少种不同的出牌方案
示例1输入
1
AAAA234567890JQKK
输出
105
说明
单个牌:17种,A,A,A,A,2,3,4,5,6,7,8,9,0,J,Q,K,K
对子:7种,AA,AA,AA,AA,AA,AA,KK(注意A的不同)
炸弹:1种,AAAA
三带一:52种
三带二:4种,AAAKK, AAAKK, AAAKK, AAAKK
五单顺子:24种
总共:105种
思路
因为有除了数字以外的其他字符所以就不能用整型去输入
于是乎我使用了快读(快速读入)的变式
因为这些字符其实是有大小顺序的,所以通过判断字符给他们配对上相应大小的数值
然后由于看别人的解析太多了…看到这种题就想到要把他们排好序
就使用了qsort函数从小到大排好
接下来就是CnkC^k_nCnk的排列组合的高中知识
5单顺子这个由于我没审题…还以为是打出顺子…就在想单牌和对牌的顺子以及大于等于5的要怎么解决.等我写出来再看题才发现…淦
代码#include
#include
#include
int read() {
char a = getchar();
switch (a) {
default:return a - '2';
case '0':return 8;
case 'J':return 9;
case 'Q':return 10;
case 'K':return 11;
case 'A':return 12;
case '2':return 13;
}
}
int cmp(const void* a, const void* b) {
return *(int*)a - *(int*)b;
}
int sum = 1;
int contain = 0;
int mun[17];
int main() {
int t;
scanf("%d", &t);getchar();
int num = 0;
int four = 0, three = 0, two = 0, one = 0;
while (t--) {
memset(mun, 0, sizeof(int) * 17);
for (int i = 0; i < 17; i++)
mun[i] = read();
getchar();//忘记吸收enter键
qsort(mun, 17, sizeof(int), cmp);
for (int i = 0, j; i < 16; i++) {
for (j = 1, num = 1; j <= 4;j++, i++)
if (mun[i] == mun[i + 1]) num++;
else break;
if (num == 4) four++;
if (num == 3) three++;
if (num == 2) two++;
if (num == 1) one++;
}
one++;
contain += 17;
contain += two + three * 3 + four * 6;
contain += four;
contain += three * 14 + four * 4 * 13;
contain += three * (two + four * 6 + (three - 1) * 3) + four * 4 * (two + three * 3 + (four - 1) * 6);
int times[17] = { 0 };
for (int i = 0, j = 0, k = 0; i < 17; i++)
if (mun[i] == mun[j]) times[k]++;
else {
if (mun[i] == mun[j] + 1) times[++k]++;
else times[++++k]++;
j = i;
}
for (int i = 0;i < 13;i++) {
for (int j = 0;j <= 4;j++)
sum *= times[i + j];
contain += sum;
sum = 1;
}
printf("%d\n", contain);//没加换行一直报错
contain = num = one = two = three = four = 0;//忘记归零
}
return 0;
}
总结
感觉自己思路和解题方式有了提高,奈何将思路转化为代码的能力还是欠缺,写的过程基本上都是摸鱼,单纯的在想不知道要怎么把思路弄成代码的形式.以后可能要多练练
操作过程还是很多细节没做好花了很多时间,比如没有将enter
吸收,输出没有\n
没有将数值归零
代码还可以再省一点,把for (int i = 0, j; i < 16; i++)
和for (int i = 0, j = 0, k = 0; i < 17; i++)
这两个判断条件合并可以减少循环次数