洛谷 P11227:[CSP-J 2024] 扑克牌 - C++题解

该文章已生成可运行项目,

原题链接:https://www.luogu.com.cn/problem/P11227

一、题目简化版本


题目描述

给出你有的几张扑克牌(不含大小王),以两个字符表示:

  • 第一个字符表示花色,是 SHCD 中的一个,分别表示黑桃、红桃、草花、方片。
  • 第二个字符表示点数, 1 ∼ 13 1\sim13 113 可以表示为 A23456789TJQK

求你没有的扑克牌数量。

输入格式

1 1 1 行:一个 n n n,表示给出的扑克牌数。
2 ∼ n + 1 2\sim n+1 2n+1 行:每行两个字符(见题目描述介绍),表示有的扑克(可能重复)。

输出格式

一行,你没有的扑克牌数量。

输入输出样例

输入 #1

1
SA

输出 #1

51

输入 #2

4
DQ
H3
DQ
DT

输出 #2

49

提示说明

一幅不含大小王的扑克牌有 52 52 52 张。

二、题解


在这里插入图片描述
这是题目给出的数据范围。

测试点1~4(40pts)


测试点 1 ∼ 4 1\sim4 14 保证输入的扑克两两不同,因此不会出现重复,用 52 − n 52-n 52n 即可。

代码

#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 种方法都可以有效去重。

创作不易,点个赞吧👍

在这里插入图片描述

在这里插入图片描述

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值