OpenJudge - 6377:生日相同 2.0http://noi.openjudge.cn/ch0301/6377/
拿到题,读一遍,了解个大概,进行
数据结构!!!
在正常的算法竞赛学习过程中,我们先后会学到(常用的几种):
① 数组
② 结构体
③ 联合体
……
那么这道题,输入成分相似,而且分类明确,集合性强。用什么?(大声回答)
当然是结构体(当然数组也能用,不过比较复杂,本篇中不多赘述)
结构体怎么用?(某人:“不知道”)
这样的人估计有很多,如果你也是这样的人,请去这个网站学习一下[旺柴]:
【官方 MV】Never Gonna Give You Up - Rick Astley_哔哩哔哩_bilibili-, 视频播放量 83747542、弹幕量 117933、点赞数 2190126、投硬币枚数 932189、收藏人数 1152828、转发人数 341823, 视频作者 索尼音乐中国, 作者简介 更多音乐请右滑收藏夹~欢迎投稿字幕,相关视频:KANA-BOON「バトンロード」(TV动画《博人传 火影忍者新时代》OP),大家好,我是Rick Astley,今天我入驻b站了! doge,当我们在校园合唱节中唱你被骗了……,【官方MV】LiSA「紅蓮華」(TV动画《鬼灭之刃》OP),King Gnu「BOY」(TV动画《国王排名》OP),【年龄和声音终于一致了】rick应邀重新演绎经典MV,2024开年诈骗!Rick Astley《Never Gonna Give You Up》 摇滚跨年夜 20240101,油管官方惨遭Rickroll,【8K】MV 宮本浩次 《冬之花》「冬の花」—— 收藏级画质,【春节】刘德华《恭喜发财》春节必听神曲!祝大家新年快乐!https://www.bilibili.com/video/BV1GJ411x7h7/?spm_id_from=333.337.search-card.all.click(愿者上钩)
既然知道了这道题用结构体,定义它,就迈出了第一步。
要特别注意数据类型、输出格式、特殊值等规定。
比如说
1.输入表示有n个学生,n ≤ 180。这就告诉我们无需定义太多的结构体空间;但若是定义正好180个,这是一种不好的做法。大部分程序设计者无法一次性非常准确地控制好访问边界,特别容易访问超区。如果你不是很会控制和统计空间数量/长度,那应该留出宽限,所以应该空出几十个空空间(但这并不是说你可以不认真统计使用数量)。对于本题,差不多
Stu stu[200];
就够了
2.输入顺序:名字(string)、月(int)、日(int),出生月(1 ≤ m ≤ 12)、日(1 ≤ d ≤ 31)。单空格分隔。
3.输出顺序:
相同的生日(月+空格+日)+空格+所有在当天出生的学生的名字;
相同的生日(月+空格+日)+空格+所有在当天出生的学生的名字;
相同的生日(月+空格+日)+空格+所有在当天出生的学生的名字;
……
日期从前到后(很重要),名字按名字从短到长按序输出,长度相同的按字典序(就是字符串对应位置元素的ASCII码比较)输出。如没有生日相同的学生,输出”None”。
很明显:如果只有一个人出生于一个单独的生日,那这个生日的日期和这个人的名字都不应输出。
这一步不讲了
#include
using namespace std;
int main()
{
//sentences
return 0;
}
很明显,该结构体需要包括名字、出生月、出生日几个成分。它们的类型分别是string(这里不推荐用数组或其它的), int , int。
struct Stu
{
string ftn;//ftn是first name的缩写
int mon;//month
int dat;//date,实际上用day更好,这里就不改了
}stu[200];//特别要注意两个大小写不同的Stu和stu,Stu是类型名,而stu是变量名
数量值输入不用说,挨个填入数据也是简单的。
然后,数据有了,你该怎么办?
如果你直接进行统计,需要建很多的表示月、日、数量统计、名字统计的变量。
如此繁杂,那就是因为数据无序。
该触发关键词了——排序。
特别要注意的是排序的下标。如果下标从1开始,那应该从哪几个元素开始排序呢(请各位思考一下)
结构体排序,少不了?(大声回答)答:cmp函数。
本题的cmp函数直接按输出要求排列好就可以。
写cmp函数需要注意:①把分支结构思路理清晰;②将比较量选对;③将返回值类型写对。
bool cmp(Stu a, Stu b)/这里可以理解为比较的是类数组元素的前、后两个元素
{
if (a.mon != b.mon) return a.mon < b.mon;//月份不同,小的在前
else if (a.dat != b.dat) return a.dat < b.dat;//月份相同,日子不同,小的在前
else if (a.ftn.size() != b.ftn.size()) return a.ftn.size() < b.ftn.size();
//生日完全相同,名字长度不同,短的在前
else return a.ftn < b.ftn;//以上均相同,名字字母逐个比较,相对小的在前
//return一定要写成对应量的大小关系,而不是两个结构体的大小关系,不然编译器提示重载错误
}
then:排序后可以进行输出测试,测试完注释掉。
then:写上下一个for()开始设计输出。
咱们要想一个问题:什么样的数据,有什么样的特征,怎么处理它?
1.现在排好顺序的数据,月日罗列整齐,生日单调递增。那这样的数列如何判断日期是单独(即只有一个人出生在这天)的呢?
很简单,大家看这个数列
6,6,6,6,6,6,6,6,7,9,9,9,9,9,9,…
中间的这个7,上面一项与他不相等,下面一项也与它不相等。那么他就是单独的(确信)。
2.那如果他与上面一项的不相等,那至少说明什么?
答:他的生日与上一项不同,是一个新数列的开端。
题目规定了,所有组别要先输出生日,那你要用bool控制一下,如果是一个开端,就这么做。但必须注意,这种情况,包括了上一种情况。
我说了这么多话,但你却没被绕进去,原因——很多重复使用的句子。
那很多聪明的人(比如我)会想到一个办法,咱们用两个布尔变量代表两个判断句。
假设说A=某个人和他上面的人(结构体)生日完全相同,B=A=某个人和他上面的人(结构体)生日完全相同。
那第一种情况可以视为!A&&!B,或写作!(A||B);第二种情况可以视为!A。
而遇到第一种情况,就别浪费时间了,写在前面,直接continue;
遇到第二种情况,注意,此时的第二种情况不包括第一种情况了(因为已经continue),所以直接输出日期+名字,注意格式(比如空格)。
如果是其他的情况(A为真),直接输出名字即可,但如果出现(A&&!B)的现象,表明到了末尾,直接加换行。但注意这两种情况是不冲突的,所以写为:
if(A)
{
cout<
但是如果什么都没输出怎么办,不能空着。
我这回没有好点子了,加一个变量控制是否输出,只要输出(只要有cout),该变量就是true;如果是false,输出None,注意大小写。
#include//万能头
using namespace std;
struct Stu
{
string ftn;
int mon;
int dat;
}stu[200];
bool cmp(Stu a, Stu b)
{
if (a.mon != b.mon) return a.mon < b.mon;
else if (a.dat != b.dat) return a.dat < b.dat;
else if (a.ftn.size() != b.ftn.size()) return a.ftn.size() < b.ftn.size();
else return a.ftn < b.ftn;
}
bool A,B,ne=false;//两个说法,A为向上判断,B为向下判断,ne控制是否有输出(是否有相同)
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> stu[i].ftn >> stu[i].mon >> stu[i].dat;
sort(stu + 1, stu + 1 + n, cmp);
// for(int i=1;i<=n;i++)
// cout<
Tips
1.原创内容,禁止盗用,如需转载请注明出处;
2.有错敬请指正,欢迎讨论区交流。