PAT (Basic Level) Practice (中文)1065 单身狗 (25 分) 凌宸1642
题目描述:
“单身狗”是中文对于单身人士的一种爱称。本题请你从上万人的大型派对中找出落单的客人,以便给予特殊关爱。
输入格式:
输入第一行给出一个正整数
N(≤ 50 000),是已知夫妻/伴侣的对数;随后N行,每行给出一对夫妻/伴侣——为方便起见,每人对应一个
ID号,为5位数字(从00000到99999),ID间以空格分隔;之后给出一个正整数
M(≤ 10 000),为参加派对的总人数;随后一行给出这M位客人的ID,以空格分隔。题目保证无人重婚或脚踩两条船。
输出格式:
首先第一行输出落单客人的总人数;随后第二行按
ID递增顺序列出落单的客人。
ID间用1个空格分隔,行的首尾不得有多余空格。
输入样例:
3
11111 22222
33333 44444
55555 66666
7
55555 44444 10000 88888 22222 11111 23333
输出样例:
5
10000 23333 44444 55555 88888
题目要求:
作者 CHEN, Yue
单位 浙江大学
代码长度限制 16 KB
时间限制 200 ms
内存限制 64 MB
坑点:
- 对于夫妻客人的存储的时候,首先我也选择了使用
map<int , int >但是题目中 客人 的ID值可以是0,
这会出现什么问题呢? 若刚好某个人的 ID 值是 0 的话,当我们查找 map的时候,返回的0 值 不好判断
是没有这个客人 , 还是找到了符合要去的对象 ID 解决方法很简单,可以多输入的时候如果 ID 是 0 的话
我们转化为另外一个数即可,但这样会需要增加很多的判断,所以我采用了 map<string , string>
-
存储那些 有对象但是不确定其对象是否在场的时候,我首先采取的是,直接使用
vector来进行存储,在检查其对象是否在场的时候,会需要依次比对(就算使用
sort函数,写二分查找也会耗很多时间) ,(题主注意是
懒,没有去尝试用二分,所以运行超时了)。 所以选择了直接再用一个map<string , int>注意找不到的时候会返回
0,所以我们int存储时,不能存储0 -
如果这样还是会
超时的话, 就将所有的cin cout换成scanf printf这里需要知道的是,利用
scanf进行输入string类型时,需要确定分配内存的大小,不然会报错然后进行
printf输出string类型的时候,要利用c_str()函数,转换为字符数组输出。
解题思路:
存储各夫妻对应关系
/*
1. 一看题目找 单身狗 ,瞬间觉得好简单,不就是把没有 对象 的人拎出来,哈哈哈哈哈
题目中明确没有一个人有两个人对象的情况,那么久可以很自然的想到一对夫妻是一一对应的。
一对一对的存储,很容易想到使用 map 来存储夫妻的 key 和 value ,
而题目中明确说明,夫妻是一一对应的,也就是 可以通过 value 找到 key ,
所以说如一对夫妻的时候,我们就把 夫妻分别作为 key 和 value 的 map 存储起来。
至于 map 中的数据类型,我选择了使用 string 对应 string
*/
a.resize(5);
b.resize(5);
t.resize(5); // 重新分配内存,为了使用 scanf 对 string 类型进行输入。
while(n--){
scanf("%s %s" , &a[0] , &b[0]) ;
mp.insert(pair<string , string>( a , b )) ; // 插入《夫,妻》
mp.insert(pair<string , string>( b , a )) ; // 插入《妻,夫》
}
找出落单客人
/*
2. 然后就应该是找出里面的单身狗啦 这一步的处理,我分成了两部分来进行。
第一部分,这里需要理解好 落单客人 和 单身狗 的区别。
落单客人 包括 单身狗 以及 有对象但是其对象不在现场的客人。
存储满足要求的落单客人 输出时要按照 ID 的升序,故采用 set 容器进行存储
*/
for(int i = 0 ; i < k ; i ++){
scanf("%s" , &t[0]) ;
if(mp[t] == "") // 如果夫妻关系 map 里面没有这个人的对象,那么他是单身狗,符合要求,加入 st
st.insert(t) ;
else { // 如果他是有对象的人,先记录下来,待会再来检查一下他对象在不在场
cus.push_back(t) ;
test.insert(pair<string , int>(t , i + 1)) ; // 给他安排一个序号 (从 1 开始)
}
}
/*
第二部分,就是从第一部分里面记录的有对象的客人,如果他的对象不在场,那么久加入落单客人行列中。
在 mp 中找到 cus[i] 的夫/妻的 ID,根据此 ID 查找我们第一部分时给他的序号 ,
若果序号不为 0 说明 他们夫妻均在场 (找不到序号的时候返回 0 )
找不到序号的时候,那就说明他今晚是 落单客人,得加入 落单客人 的行列中。
*/
for(int i = 0 ; i < cus.size() ; i++)
if(test[mp[cus[i]]] != 0)
continue ;
else st.insert(cus[i]) ;
按要求输出落单客人 ID
printf("%d\n" , st.size()) ; // 打印落单客人的人数
int i = 1 ;
// 通过迭代器访问 set 中的元素
for(set<string>::iterator it = st.begin(); it != st.end() ;i++, it++){
printf("%s%c",(*(it)).c_str() , (i != st.size())?' ':'\n');
}
完整代码
#include<bits/stdc++.h>
using namespace std ;
map<string , string> mp ;
map<string , int> test ;
set<string> st ;
vector<string> cus ;
int n , k ;
string a , b , t ;
int main(){
scanf("%d" , &n) ;
a.resize(5) ;
b.resize(5) ;
t.resize(5) ;
while(n--){
// scanf("%d %d", &a , &b ) ;
scanf("%s %s" , &a[0] , &b[0]) ;
mp.insert(pair<string , string>(a , b)) ;
mp.insert(pair<string , string>(b , a)) ;
}
scanf("%d" , &k) ;
for(int i = 0 ; i < k ; i ++){
scanf("%s" , &t[0]) ;
if(mp[t] == "")
st.insert(t) ;
else {
cus.push_back(t) ;
test.insert(pair<string , int>(t , i + 1)) ;
}
}
// for(int i = 0 ; i < cus.size() ; i++){
// cout<<cus[i]<<endl ;
// }
for(int i = 0 ; i < cus.size() ;i ++)
if(test[mp[cus[i]]] != 0) continue ;
else st.insert(cus[i]) ;
printf("%d\n" , st.size()) ;
int i = 1 ;
for(set<string>::iterator it = st.begin() ; it != st.end() ;i++ , it++)
printf("%s%c" , (*(it)).c_str() , (i != st.size())?' ':'\n') ;
return 0 ;
}
该博客介绍了如何解决PAT(BasicLevel)Practice中的1065题——单身狗问题。博主通过C++编程,利用map和set数据结构,找出大型派对中单身及伴侣不在场的客人。关键步骤包括存储夫妻关系、找出落单客人并按升序输出。博客还分享了在处理ID为0时的注意事项以及可能的优化方法。
276

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



