前言
今天讲讲日期问题,所谓日期问题,在蓝桥杯中出现众多,但是解法比较固定。
一般有判断日期合法性,判断是否闰年,判断日期的特殊形式(回文或abababab型等)
目录
例题
题2
题三
总结
先枚举日期,再根据题意判断,而不是先模拟题意进行构造日期
判断日期合法性(月份判断,日判读,闰年判断等)
从一个八位数中一次取出年月日
例题
回文日期
题目的本意是在给定date1与date2之间找出所有的回文日期的个数
对于一个回文日期
对于此题,我们有两种思路
①是构造回文日期,判断日期合法性,再计算符合范围的回文日期的个数。
②是先从全部枚举日期,构造回文日期,再判断日期的合法性与找出符合条件日期。
这里判断日期的合法性指,月份必须要在12月内,
日必须要在对应月份合理的天数,在此还需要判断是否是闰年。
显然思路①明显比较困难, 构造回文日期比较难,所以我们采取思路2
所以大致思路如下:
枚举日期时候,我们只需枚举年份(从1000到9999)(即前四位)
通过年份构造回文日期时,有以下思路
for(int i=1000;i<=9999;i++)
{
int s=i,x=i;
for(int k=0;k<4;k++)
{
s=s*10+x%10;//x模运算是依次取出每一个数
x=x/10;
}
if(date1<=s && s<=date2 && check(s)){res++;}
}
一个例子:
代码如下:
#include<cstdio>
int arr[]={0,31,28,31,30,31,30,31,31,30,31,30,31};//月份对应天数
bool check(int date)
{
int year=date/10000;
int month=date%10000/100;
int day=date%100;
if(month==0||month>12){return false;}
if(day==0||month!=2 && day>arr[month]){return false;}
if(month==2)//2月需要特判
{
int j= year%400==0||year%4==0&&year%100!=0;//是闰年j为1,否则为0
if(day>arr[month]+j||day<1){return false;}
}
return true;
}
int main()
{
int date1,date2;
scanf("%d%d",&date1,&date2);
int res=0;
for(int i=1000;i<=9999;i++)
{
int s=i,x=i;
for(int k=0;k<4;k++)
{
s=s*10+x%10;
x=x/10;
} //此时s为回文日期
if(date1<=s && s<=date2 && check(s)){res++;}
}
printf("%d",res);
}
题2
回文日期2
题目本意是给出一个日期,寻找下一个回文日期和ABABBABA型的日期
我们分析ABABBABA型有特殊性,它也是回文日期,
这样我们在回文日期种在判断它是否是ABABBABA型即可。
对于判读ABABBABA型, 有以下条件:
它的个位数与十位数不相等,个位数与百位数相等,十位数与千位数相等。
代码如下:
#include<cstdio>
int arr[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool check(int i)//判断日期合法性
{
int year=i/10000,month=i%10000/100,day=i%100;
if(month==0||month>12){return false;}
if(month!=2 && day>arr[month]||day==0){return false;}
if(month==2)
{
int j=year%400==0||year%4==0&&year%100!=0;
if(day>arr[month]+j||day==0){return false;}
}
return true;
}
int main()
{
int n;
scanf("%d",&n);
int acc=0,abb=0;//判断是否第一次出现回文日期和ABABBABA式日期
for(int i=n/10000;;i++)//要一直循环
{
int x=i,j=i;
for(int k=0;k<=3;k++)
{
x=x*10+j%10;
j=j/10;
}
//x为构造后的回文日期
if(check(x)&&x>n)//判读日期合法性,判断日期大于给定日期
{
if(acc!=1){printf("%d\n",x);acc=1;}//第一次输出回文日期
int num1 = x%10, num2 = x/10%10, num3=x/100%10, num4=x/1000%10;
//分别取个,十,百,千位数
if(abb!=1&&num2!=num1&&num1==num3&&num2==num4)//判断ABABBABA
{
printf("%d\n",x);
abb=1;
}
if(acc==1&&abb==1){break;}//找完跳出循环
}
if(acc==1&&abb==1){break;}
}
}
题三
日期问题(困难)
例如:
输入: 02/03/04
输出:2002-03-04
2003-02-03
2004-03-04
本题:对于输入而言,有三种情况:年/月/日,日/月/年/,月/日/年
本题中如果对给出的输入模拟出可能出现的日期比较困难,不妨采取先枚举所有日期,
判断日期合法性,然后判断这些日期是否在给定输入的可能值里面。
代码如下
#include<cstdio>
int arr[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool check(int year,int month,int day)
{
if(year<1960||year>2059)return false;
if(month<1||month>12)return false;
if(month!=2)
{
if(day>arr[month]||day<1) return false;
}
else
{
int leap= year%4==0&&year%100!=0 || year%400==0;//闰年leap为1;
if(day>arr[month]+leap||day<1){return false;}
}
return true;
}
int main()
{
int a,b,c;
scanf("%d/%d/%d",&a,&b,&c);
for(int i=19600101;i<=20591231;i++)//枚举所有日期
{
int year=i/10000,month=i%10000/100, day=i%100;//取出年月日
if(check(year,month,day))//判断日期合法性
{
int yea=year%100;//取出年份的后两位
if(yea==a&&month==b&&day==c||yea==c&&month==a&&day==b||
yea==c&&month==b&&day==a)//判断可能的值
{
printf("%d-%02d-%02d\n",year,month,day);//格式化输入
}
}
}
return 0;
}
注意这里输出与输入
··scanf ("%d /%d/ %d",&a ,&b ,&c); //过滤掉输入的 /
··printf ("%d-%02d-%02d\n" , year,month,day); //%02d意为输出两位,不足两位补上前导0
总结
这三到题都有很大的相似性
-
先枚举日期,再根据题意判断,而不是先模拟题意进行构造日期
-
判断日期合法性(月份判断,日判读,闰年判断等)
bool check(int date)//一个八位的日期包含年月日
{
int year=date/10000; //取出年
int month=date%10000/100; //取出月
int day=date%100; //取出日
if(month==0||month>12){return false;}
if(day==0||month!=2 && day>arr[month]){return false;}
if(month==2)//2月需要特判
{
int j= year%400==0||year%4==0&&year%100!=0;//是闰年j为1,否则为0
if(day>arr[month]+j||day<1){return false;}
}
return true;//其他为合法日期,返回真
}
-
从一个八位数中一次取出年月日
例如20201018------取2020年取10月取18 日
其中有公式 运算:
%10^n ························取出一个数的后n位
/ 10^n ························取出一个数的前n位
//date为一个八位数
int year=date/10000; //取出年
int month=date%10000/100; //取出月
int day=date%100; //取出日
本篇博客到此结束,谢谢大家观看,如果各位博友们有好的建议或好的想法,
欢迎留言喔,谢谢大家!