C语言PAT刷题 - 1028 人口普查

作者的话:若有朋友复制代码去PAT试着运行遇到问题的:
1.可能是格式问题,可以先把从本站复制的代码粘贴到记事本,再把记事本里的代码复制,然后粘贴到PAT的代码区,提交本题回答,应该就可以了;
2.可能是注释原因,PAT有时候检测到注释会编译错误,所以可以先把注释删了,再进行提交回答;
3.可能是作者当初根据题目写出来的代码仍存在一些疏漏,而恰好当时的测试机制没那么完善,没检测出问题。后面测试机制有所更新,故出现问题,若有相关需要的可以评论区留言或私信作者,我看到的话会去再查一下疏漏之处,然后更新文章。

一、题目描述
某城镇进行人口普查,得到了全体居民的生日。现请你写个程序,找出镇上最年长和最年轻的人。
这里确保每个输入的日期都是合法的,但不一定是合理的——假设已知镇上没有超过 200岁的老人,而今天是2014年9月6日,所以超过200岁的生日和未出生的生日都是不合理的,应该被过滤掉。
输入格式:
输入在第一行给出正整数 N,取值在(0,105];随后 N 行,每行给出1个人的姓名(由不超过5个英文字母组成的字符串)、以及按 yyyy/mm/dd(即年/月/日)格式给出的生日。题目保证最年长和最年轻的人没有并列。
输出格式:
在一行中顺序输出有效生日的个数、最年长人和最年轻人的姓名,其间以空格分隔。
输入样例:
5
John 2001/05/12
Tom 1814/09/06
Ann 2121/01/30
James 1814/09/05
Steve 1967/11/20
输出样例:

3 Tom John

二、解题思路
读题:

//接收正整数N,表示后面N行会给出总共N个人的姓名和生日。
//接收姓名(<=5个字母)+生日(yyyy/mm/dd)
//输出有效生日的个数+最年长的人的姓名+最年轻的人的姓名(空格相隔)
//要求:设定今天是2014.9.6,超过两百岁的生日和未出生的生日都是无效生日
思路:
1.定义结构体Person,成员是存储姓名的字符串数组a和存储生的变量year,month,day;
2.定义需要的变量并接收n;
3.把n赋值给count(后面会检测每个输入的生日,若为无效生日,则count–,当检测完所有生日后,count的值就是有效生日的个数);
4.设置循环,循环进行n轮,每轮循环接收一行数据,并检测接收的数据是否为有效生日。把当轮循环及之前接收的有效生日中的最早生日(年纪最大)和最晚生日(年纪最小)找出来存在max,min中;
5.按要求格式进行输出。

三、具体实现
0.标准C源程序框架

#include <stdio.h>
#include <string.h>//要用到strcpy函数
int main()
{
    return 0;
}

1.定义结构体Person,成员是存储姓名的字符串数组a和存储生日的变量year,month,day;

typedef struct Person
{
	char a[6];//存储最多5个字母+'\0'
	int year, month, day;//存储年月日
}Person;

2.定义需要的变量并接收n;

	int n;//存储N
	int i = 0;//循环变量
	int count;//存储有效生日的个数
	//初始化max,min,并控制初值在后面一定能被有效数据所覆盖
	Person max = { "",3000,1,1 }, min = { "",0,1,1 }, temp;
	scanf("%d", &n);

3.把n赋值给count(后面会检测每个输入的生日,若为无效生日,则count–,当检测完所有生日后,count的值就是有效生日的个数);

	count = n;//开始默认所有数据都为有效生日

4.设置循环,循环进行n轮,每轮循环接收一行数据,并检测接收的数据是否为有效生日。把当轮循环及之前接收的有效生日中的最早生日(年纪最大)和最晚生日(年纪最小)找出来存在max,min中;

	while (i < n)
	{
		scanf("%s", temp.a);//接收当前行的姓名和生日
		scanf("%d/%d/%d", &temp.year, &temp.month, &temp.day);
		if (temp.year < 1814//生于1814年以前的,已经超过200岁,属于无效生日
			|| ((temp.year == 1814) && ((temp.month < 9) || ((temp.month == 9) && (temp.day < 6))))//1814年出生,出生的月份或日期早于200年前的今天的,也是无效生日
			|| ((temp.year == 2014) && ((temp.month > 9) || ((temp.month == 9) && (temp.day > 6))))//同在今年,今天之后的日期
			|| temp.year>2014)//今年之后的年份
		{
			count--;//前面条件表达式若为真,说明当前输入为无效生日
		}
		else//确定当前接收生日是有效生日时
		{
			if ((temp.year < max.year)//比当前最早出生年份更小的,是年龄更大的
				|| ((temp.year == max.year) && (temp.month < max.month))//月份
				|| ((temp.year == max.year) && (temp.month == max.month) && (temp.day < max.day)))//日期
			{
				strcpy(max.a, temp.a);
				max.year = temp.year;
				max.month = temp.month;
				max.day = temp.day;
			}//找到年龄更大的人,把其的数据赋值给max
			if (temp.year > min.year//比当前最晚出生年份更大的,是年龄更小的
				|| ((temp.year == min.year) && (temp.month > min.month))
				|| ((temp.year == min.year) && (temp.month == min.month) && (temp.day > min.day)))
			{
				strcpy(min.a, temp.a);
				min.year = temp.year;
				min.month = temp.month;
				min.day = temp.day;
			}
		}
		i++;
	}

5.按要求格式进行输出。

	if (count)//当所有数据都为无效生日的时候,不存在最年长者和最年轻者,不需要输出他们的名字
		printf("%d %s %s", count, max.a, min.a);
	else
		printf("%d", count);

四、测试数据
输入输出样例1:如题

输入样例2:(当所有数据都无效的时候,不需要输出最年长者和最年轻者的名字,只需要输出0,后面不能有任何符号)(测试点3)
1
Mike 0000/00/00
输出样例2:
0

五、全部代码

#include <stdio.h>
#include <string.h>//要用到strcpy函数
typedef struct Person
{
	char a[6];//存储最多5个字母+'\0'
	int year, month, day;//存储年月日
}Person;
int main()
{
	int n;//存储N
	int i = 0;//循环变量
	int count;//存储有效生日的个数
	//初始化max,min,并控制初值在后面一定能被有效数据所覆盖
	Person max = { "",3000,1,1 }, min = { "",0,1,1 }, temp;
	scanf("%d", &n);
	count = n;//开始默认所有数据都为有效生日
	while (i < n)
	{
		scanf("%s", temp.a);//接收当前行的姓名和生日
		scanf("%d/%d/%d", &temp.year, &temp.month, &temp.day);
		if (temp.year < 1814//生于1814年以前的,已经超过200岁,属于无效生日
			|| ((temp.year == 1814) && ((temp.month < 9) || ((temp.month == 9) && (temp.day < 6))))//1814年出生,出生的月份或日期早于200年的今天的,也是无效生日
			|| ((temp.year == 2014) && ((temp.month > 9) || ((temp.month == 9) && (temp.day > 6))))//今年今天之后的日期
			|| temp.year>2014)//今年之后的年份
		{
			count--;//前面条件表达式若为真,说明当前输入为无效生日
		}
		else//确定当前接收生日是有效生日时
		{
			if ((temp.year < max.year)//比当前最早出生年份更小的,是年龄更大的
				|| ((temp.year == max.year) && (temp.month < max.month))//月份
				|| ((temp.year == max.year) && (temp.month == max.month) && (temp.day < max.day)))//日期
			{
				strcpy(max.a, temp.a);
				max.year = temp.year;
				max.month = temp.month;
				max.day = temp.day;
			}//找到年龄更大的人,把其的数据赋值给max
			if (temp.year > min.year//比当前最晚出生年份更大的,是年龄更小的
				|| ((temp.year == min.year) && (temp.month > min.month))
				|| ((temp.year == min.year) && (temp.month == min.month) && (temp.day > min.day)))
			{
				strcpy(min.a, temp.a);
				min.year = temp.year;
				min.month = temp.month;
				min.day = temp.day;
			}
		}
		i++;
	}
	if (count)//当所有数据都为无效生日的时候,不存在最年长者和最年轻者,不需要输出他们的名字
		printf("%d %s %s", count, max.a, min.a);
	else
		printf("%d", count);
	return 0;
}

六、优化代码
//运行速度变化不大,但是我觉得代码可读性应该增强了,代码量也有相应减少。

#include <stdio.h>
#include <string.h>//要用到strcpy函数
typedef struct Person
{
	char a[6];//存储最多5个字母+'\0'
	int birth;//存储生日
}Person;
int main()
{
	int n;//存储N
	int i = 0;//循环变量
	int count;//存储有效生日的个数
	int year, month, day;
	//初始化max,min,并控制初值在后面一定能被有效数据所覆盖
	Person max = { "",30000101 }, min = { "",00000101 }, temp;
	scanf("%d", &n);
	count = n;//开始默认所有数据都为有效生日
	while (i < n)
	{
		scanf("%s", temp.a);//接收当前行的姓名和生日
		scanf("%d/%d/%d", &year, &month, &day);
		temp.birth = year*10000+month*100+day;//把年月日三个数据整合成一个整数,以此更方便的比较生日早晚
		if (temp.birth<18140906||temp.birth>20140906)  count--;//前面条件表达式若为真,说明当前输入为无效生日
		else//确定当前接收生日是有效生日时
		{   
			if(temp.birth<max.birth)//出生日期比当前年龄最大者更小,即更早,则年龄比他更大
			{
				strcpy(max.a, temp.a);
				max.birth = temp.birth;
			}//找到年龄更大的人,把其的数据赋值给max
			if (temp.birth > min.birth)//出生日期比当前年龄最小者更大,即更迟,则年龄比他更小
			{
				strcpy(min.a, temp.a);
				min.birth = temp.birth;
			}
		}
		i++;
	}
	if (count)//当所有数据都为无效生日的时候,不存在最年长者和最年轻者,不需要输出他们的名字
		printf("%d %s %s", count, max.a, min.a);
	else
		printf("%d", count);
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值