1028 人口普查 (20 分)
某城镇进行人口普查,得到了全体居民的生日。现请你写个程序,找出镇上最年长和最年轻的人。
这里确保每个输入的日期都是合法的,但不一定是合理的——假设已知镇上没有超过 200 岁的老人,而今天是 2014 年 9 月 6 日,所以超过 200 岁的生日和未出生的生日都是不合理的,应该被过滤掉。
输入格式:
输入在第一行给出正整数 N,取值在(0,10^5 ];随后 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
思路1:
int型变量N存放人数,string型数组num存放输入的名字及生日,int型数组num1存放num数组中空格的位置,int型变量count记录有效生日个数,count_max,count_min记录最晚生日和最早生日的编号,max和min记录最晚生日和最早生日日期。
第一个for循环将输入存放至num数组,第二个for循环将找到num数组中每个元素中空格的位置,并存入num1数组(为了确定名字长度),第三个for循环删去num数组中字符串的空格和‘/’,第四个for循环用以确定有效生日,最晚生日及最早生日。最后按格式输出。
参考代码1:
#include <iostream>
#include <string>
using namespace std;
int main(){
int N;
scanf("%d",&N);
string num[100010];
for(int i=0;i<=N;i++){//存储输入;
getline(cin,num[i]);
}
int num1[100010];
for(int i=1;i<=N;i++){
num1[i]=num[i].find(" ");
}
for(int i=1;i<=N;i++){//删去空格和/
num[i].erase(num1[i],1);
num[i].erase(num1[i]+4,1);
num[i].erase(num1[i]+6,1);
}
int count=0,count_min=0,count_max=0,max=18140906,min=20140906;
for(int i=0;i<=N;i++){
string str=num[i].substr(num1[i],8);
int num2=atoi(str.c_str());//atoi()l里面只能传递const char类型,需将string转化为从上图char
if(num2>=18140906&&num2<=20140906) {
if(num2>max) {
max=num2;count_min=i;
}
if(num2<min) {
min=num2;count_max=i;
}
count++;
}
}
if(count==0) printf("0");
else{
printf("%d ",count);
for(int i=0;i<num1[count_max];i++){
printf("%c",num[count_max][i]);
}
printf(" ");
for(int i=0;i<num1[count_min];i++){
printf("%c",num[count_min][i]);
}
}
return 0;
}
思路2:
定义结构体person用以存储每个人的姓名及生日,lessequ和moreequ函数用来判断两个人的生日是大还是小,init函数用来初始化有效生日边界以便判断某人生日是否合法。
main函数中int型变量存放人数,num存放有效生日个数,temp临时存放某人的姓名和生日,oldest和youngest存放最年长和最年轻人的姓名和生日。
for循环中接收输入,进行有效性判断,进行最大值最小值判断,都依靠moreequ,lessequ函数。
最后按格式进行输出。
参考代码2:
#include <cstdio>
struct person {
char name[10];
int yy,mm,dd;//日期;
}oldest,youngest,left,right,temp;
//oldest,youngest 存放最年老的和最年起的人,left和right存放合法日期边界;
bool lessequ(person a,person b){//如果a的日期小于等于b,则返回true;
if(a.yy!=b.yy) return a.yy<=b.yy;
else if(a.mm!=b.mm) return a.mm<=b.mm;
else return a.dd<=b.dd;
}
bool moreequ(person a,person b){//如果a的日期大于等于b,则返回true;
if(a.yy!=b.yy) return a.yy>=b.yy;
else if(a.mm!=b.mm) return a.mm>=b.mm;
else return a.dd>=b.dd;
}
void init (){
youngest.yy=left.yy=1814;
oldest.yy=right.yy=2014;
youngest.mm=oldest.mm=left.mm=right.mm=9;
youngest.dd=oldest.dd=left.dd=right.dd=6;
}
int main(){
init();//初始化;
int n, num=0;//统计存放合法日期的人数
scanf("%d",&n);
for (int i=0;i<n;i++){
scanf("%s %d/%d/%d",&temp.name,&temp.yy,&temp.mm,&temp.dd);
if(moreequ(temp,left)&&lessequ(temp,right)){
num++;
if(lessequ(temp,oldest)) oldest =temp;//更新oldest;
if(moreequ(temp,youngest)) youngest=temp;//更新youngest
}
}
if(num==0) printf("0\n");
else printf("%d %s %s\n",num,oldest.name,youngest.name);
return 0;
}
点评:
①此题属于查找元素型,将数据输入数组中,按题目要求进行查找输出即可。
②思路1采用了字符串数组的方式,用getline进行字符串输入,string.find()用来查找空格位置,string.erase()用来删除空格和/,string.substr()用来截取字符串的子串,atoi(char)用来把char类型转化成int型,提取出日期的整数再进行生日的一系列判断就简单多了。
③思路2采用常规定义struct的做法,oldest,youngest,left,right,temp分别存放最年老,最年轻,最早,最晚,以及临时的某个人信息。利用lessequ和moreque函数就可以统计有效生日和计算出最年老最年轻的人。思路2应作为模板记住并熟练使用。