[问题描述]
大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210。后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。
这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?
高斯出生于:1777年4月30日。
在高斯发现的一个重要定理的日记上标注着:5343,因此可算出那天是:1791年12月15日。
高斯获得博士学位的那天日记上标着:8113
请你算出高斯获得博士学位的年月日。
提交答案的格式是:yyyy-mm-dd, 例如:1980-03-21
[我的答案]
public class MyAnswer {
public static void main(String[] args) {
@SuppressWarnings("resource")
Scanner sc=new Scanner(System.in);
int sum_day=sc.nextInt();
int initial=365-31-28-31-30+1;
int[] month_day=new int[] {31,28,31,30,31,30,31,31,30,31,30,31};
int year;
int month=4;//
int day=30;
sum_day=sum_day-initial;
year=sum_day/365;
//判断闰年
int run_year=0;
for(int i=0;i<year;i++) {
if(((i+1778)%4==0 &&(i+1778)%400!=0) || (i+1778)%400==0) {
run_year++;
}
}
sum_day=sum_day%365-run_year;
year=year+1778;
int a=0;
if((year%4==0 &&year%400!=0) || year%400==0) {
a=1;
}else {
a=0;
}
for(int i=0;i<12;i++) {
if(i==3) {
sum_day=sum_day-a;
}
if(sum_day>month_day[i]) {
sum_day=sum_day-month_day[i];
}else {
month=i;
day=sum_day;
}
}
month=month+1;
System.out.println(year+"-"+month+"-"+day);
}
}
在上面的代码中,有几个错误没有注意:
1.日的初值应该从1开始。而不是0。
2.我的输入最小值为246,也就是1778年1月1日开始,否则是负值。
3.在我输入246的时候,出现了1778年12月0日,所以在月份和日的计算上,都少了1。
[正确答案1]
import java.util.Scanner;
public class Answer1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int x = sc.nextInt();
int y = 1777;
int m = 4;
int d = 30;
for (int i = 2; i <= x; i++) {
d++;
if (m == 2 && ((isLeap(y) && d == 30)||(!isLeap(y) && d == 29))) {
//闰年的2月的30日等于3月1日,非闰年的2月29日相当于3月1日
m=3;
d=1;
} else if (m==12&&d==32) { //12月32日相当于下一年的1月1日
y++;
m=1;
d=1;
}else if (d == 32 && (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10) )
{
//大月的32日等于次月的1日s
m++;
d = 1;
} else if (d == 31 && (m == 4 || m == 6 || m == 9 || m == 11))
{
//小月的31日等于次月的1日
m++;
d = 1;
}
}
System.out.println(y+"-"+m+"-"+d);
System.out.println((2006 & 3));
}
/**
* 判断年份是否闰年
* @param year
* @return
*/
public static boolean isLeap(long year) {
return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
}
}
上面的代码逻辑是:从1777年4月30日开始加,这里有一个注意点,4月30号这一天是1,所以循环中从2开始。接着判断一些进位条件,首先是d如果等于30或31,对应上月份,然后重置月份和日。若是闰年,2月单独一个if判断语句。当月份到12且日为32,年份加一。
在这里需要提一下,判断闰年的算法中,第一个语句 (year & 3) == 0 等价于 year%4==0 ,因为按位与运算中,从第3位到最高位都是4的倍数,所以只要倒数第一、二位为00的时候,才能为0,也就不是4的倍数。
[正确答案2]
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Scanner;
public class Answer2 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int d=sc.nextInt();
Calendar day=new GregorianCalendar();
day.set(1777, 3, 30);
day.add(Calendar.DATE, d-1);
System.out.println(day.get(Calendar.YEAR )+"-"+(day.get(Calendar.MONTH)+1)+"-"+day.get(Calendar.DATE));
}
}
这是用了Java中的Calendar类(日历类),主要是其中的set、add、get三个函数。在本题中,需要考虑和验证的是,日历类中的月份是从0-11,最后输出的时候需要加1,同时在计算天数的时候,要从第二天开始算,因为4月30日是第一天。
其实,本题最保险的检验方法是,从题目中给的5343,1791年12月15日开始算,和8113差值放入add函数中,这样就能避免4月30日是第一天的难点。
[总结]
本次的题目,需要学习和注意的有以下几点:
1.闰年的判断条件(位运算符的运算技巧)。
2.计算思路,是从年-月-日计算顺序,还是日-月-年的计算顺序。
3.日历类Calendar的用法。