原题链接:https://www.luogu.com.cn/problem/P11227
一、题目简化版本
题目描述
给出你有的几张扑克牌(不含大小王),以两个字符表示:
- 第一个字符表示花色,是
S、H、C、D中的一个,分别表示黑桃、红桃、草花、方片。 - 第二个字符表示点数,
1
∼
13
1\sim13
1∼13 可以表示为
A23456789TJQK。
求你没有的扑克牌数量。
输入格式
第
1
1
1 行:一个
n
n
n,表示给出的扑克牌数。
第
2
∼
n
+
1
2\sim n+1
2∼n+1 行:每行两个字符(见题目描述介绍),表示有的扑克(可能重复)。
输出格式
一行,你没有的扑克牌数量。
输入输出样例
输入 #1
1
SA
输出 #1
51
输入 #2
4
DQ
H3
DQ
DT
输出 #2
49
提示说明
一幅不含大小王的扑克牌有 52 52 52 张。
二、题解

这是题目给出的数据范围。
测试点1~4(40pts)
测试点 1 ∼ 4 1\sim4 1∼4 保证输入的扑克两两不同,因此不会出现重复,用 52 − n 52-n 52−n 即可。
代码
#include<bits/std++.h>
using namespace std;
int main() {
int n;
cin >> n;
cout << 52 - n;
}

全部测试点(100pts)
为什么没有通过后面的测试点呢?
是因为后面的测试点给出的扑克牌有出现重复。
因此我们要进行去重的操作。
方法1
定义一个 b o o l bool bool 型的二维数组 f [ 5 ] [ 15 ] f[5][15] f[5][15] 用来存是否有这张牌( i n t int int 型的也可以,但 b o o l bool bool 型更省空间,能省则省😀)。
但是,给出的牌是两个字符,无法写进下标,需要进行转换。
在这里我们假设黑桃转换成 1 1 1,红桃转换成 2 2 2,草花转换成 3 3 3,方片转换成 4 4 4。
那么转换的部分就是这样:
bool f[5][20];
memset(f, false, sizeof f); //初始化为false
for(int i = 1; i <= n; i++) {
string s;
int s0, s1; //分别表示花色和点数
cin >> s;
//转换花色:
//注意string的下标从0开始
if(s[0] == 'S') s0 = 1;
else if(s[0] == 'H') s0 = 2;
else if(s[0] == 'C') s0 = 3;
else if(s[0] == 'D') s0 = 4;
//转换点数:
if(s[1] == 'A') s1 = 1;
else if(s[1] == 'T') s1 = 10;
else if(s[1] == 'J') s1 = 11;
else if(s[1] == 'Q') s1 = 12;
else if(s[1] == 'K') s1 = 13;
else s1 = s[1] - '0';
//赋值为true:
f[s0][s1] = true;
}
最后再枚举一遍 52 52 52 张牌,用变量 a n s ans ans 存没有的牌的数量,就可以了。
代码
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
bool f[5][20];
memset(f, false, sizeof f);
for(int i = 1; i <= n; i++) {
string s;
int s0, s1;
cin >> s;
if(s[0] == 'S') s0 = 1;
else if(s[0] == 'H') s0 = 2;
else if(s[0] == 'C') s0 = 3;
else if(s[0] == 'D') s0 = 4;
if(s[1] == 'A') s1 = 1;
else if(s[1] == 'T') s1 = 10;
else if(s[1] == 'J') s1 = 11;
else if(s[1] == 'Q') s1 = 12;
else if(s[1] == 'K') s1 = 13;
else s1 = s[1] - '0';
f[s0][s1] = true;
}
int ans = 0;
for(int i = 1; i <= 4; i++) {
for(int j = 1; j <= 13; j++) {
if(f[i][j] == false) ans++;
}
}
cout << ans;
return 0;
}

也可以把转换的部分写成函数,让代码更简洁。
#include<bits/stdc++.h>
using namespace std;
int convert(char c) {
if(c == 'S') return 1;
else if(c == 'H') return 2;
else if(c == 'C') return 3;
else if(c == 'D') return 4;
else if(c == 'A') return 1;
else if(c == 'T') return 10;
else if(c == 'J') return 11;
else if(c == 'Q') return 12;
else if(c == 'K') return 13;
else return c - '0';
} //因为花色和点数的字符没有冲突,可以写在同一个函数
int main() {
int n;
cin >> n;
bool f[5][20];
memset(f, false, sizeof f);
for(int i = 1; i <= n; i++) {
string s;
cin >> s;
f[convert(s[0])][convert(s[1])] = true;
}
int ans = 0;
for(int i = 1; i <= 4; i++) {
for(int j = 1; j <= 13; j++) {
if(f[i][j] == false) ans++;
}
}
cout << ans;
return 0;
}

方法2(map)
前面提到数组不可以用字符作为下标,但是 m a p map map 可以,只需要通过以下语句进行映射。
map <string, bool> f; //代表下标为string,值为bool
想要知道
m
a
p
map
map 函数的值的数量(长度),可以用 f.size() 获取。
代码
#include<bits/stdc++.h>
using namespace std;
int main() {
map <string, bool> f;
int n;
cin >> n;
for(int i = 1; i <= n; i++) {
string s;
cin >> s;
f[s] = true;
}
cout << 52 - f.size();
return 0;
}

提示:用数组赋值时间复杂度为 O ( 1 ) O(1) O(1),但 m a p map map 是 O ( l o g n ) O(logn) O(logn),需要谨慎使用。
方法3(unique 去重)
u n i q u e unique unique 可以对一个排序过的序列去重,并且将重复的放在末尾。
代码如下
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, ans;
string s[60];
cin >> n;
for(int i = 1; i <= n;i++) {
cin >> s[i];
}
sort(s + 1, s + n + 1); //先排序
ans = unique(s + 1, s + n + 1) - s - 1;
cout << 52 - ans;
return 0;
}

方法4(set 集合)
用 s e t set set 集合相当于自动去重。
代码如下
#include<bits/stdc++.h>
using namespace std;
int main() {
set <string> f;
int n;
cin >> n;
for(int i = 1; i <= n; i++) {
string s;
cin >> s;
f.insert(s); //加入集合
}
cout << 52 - f.size();
return 0;
}

以上 4 4 4 种方法都可以有效去重。
创作不易,点个赞吧👍



1532

被折叠的 条评论
为什么被折叠?



