例71 18歲生日
問題描述
小明的18歲生日就要到了,他當然很開心,可是他突然想到一個問題,是不是每個人從出生開始,到達18歲生日時所經過的天數都是一樣的呢?似乎并不全都是這樣,所以他想請你幫忙計算一下他和他的幾個朋友從出生到達18歲生日所經過的總天數,讓他好來比較一下,
輸入
一個數T,后面T行每行有一個日期,格式是YYYY-MM-DD,如我的生日是1988-03-07,
輸出
T行,每行一個數,表示此人從出生到18歲生日所經過的天數,如果這個人沒有18歲生日,就輸出-1,
輸入樣例
1
1988-03-07
輸出樣例
6574
(1)編程思路,
設輸入的出生日期為year年month月day日,則18歲生日是year+18年month月day日,若year+18年不是閏年,但month=2,day=29,則18歲生日不存在,輸出-1,
設所經過的天數為sum,初始時sum=0,每年至少有365天,18年,所以sum=sum+18*365;閏年有365天,因此在第year+1~year+17這17年中每個閏年加1天;若month>2,則第year+18年是閏年的話也要加1天;若month<2或者month==2但day!=29,則第year年是閏年的話也要加1天,將這些情況都考慮清楚不要遺漏,
(2)源程式,
#include <stdio.h>
int leapyear(int year)
{
if (year%4==0 && year%100!=0 || year%400==0)
return 1;
else
return 0;
}
int main()
{
int t,year,month,day,sum;
scanf("%d", &t);
while(t--)
{
scanf("%d-%d-%d", &year, &month, &day);
if (month == 2 && day == 29 && leapyear(year +18)!=1)
printf("-1\n");
else
{
sum = 365*18;
for (int i=year+1; i<year+18; i++)
sum += leapyear(i);
if (month > 2)
sum += leapyear(year + 18);
else if (month<2 || day != 29)
sum += leapyear(year);
printf("%d\n", sum);
}
}
return 0;
}
習題71
71-1 今夕何夕
問題描述
今天是2017年8月6日,農歷閏六月十五,
小明獨自憑欄,望著一輪圓月,發出了“今夕何夕,見此良人”的寂寞感慨,
為了排遣郁結,他決定思考一個數學問題:接下來最近的哪一年里的同一個日子,和今天的星期數一樣?比如今天是8月6日,星期日,下一個也是星期日的8月6日發生在2023年,
輸入
第一行為T(1 ≤ T ≤ 10000),表示輸入資料組數,
每組資料包含一個日期,格式為YYYY-MM-DD,其中YYYY ≥ 2017,日期一定是個合法的日期,
輸出
對每組資料輸出答案年份,題目保證答案不會超過四位數,
輸入樣例
3
2017-08-06
2017-08-07
2018-01-01
輸出樣例
2023
2023
2024
(1)編程思路,
目前全世界通用的歷法稱為公歷,它實質上是一種陽歷,
原始的陽歷是古埃及人創立的,最初取一年為365日,為了協調歷法年與回歸年的長度,公元前46年羅馬統治者儒略·凱撒對陽歷作了修改,制定儒略歷,公元前8年,凱撒的侄兒奧古斯都又對儒略歷作為調整,儒略歷分一年為十二個月,平年365日;年份能被4整除的為閏年,共366日,這樣,儒略歷歷年平均長度便是365.25日,同回歸年長度365.2422日相差0.07078日,400年約差3日,從實施儒略歷到十六世紀末期,累差約為10日,為了消除了這個引數,教皇格里高利十三世把儒略歷1582年10月4日的下一天定為10月15日,中間消去10天;同時還修改了儒略歷置閏法則:能被4除盡的年份仍然為閏年,但對世紀年(如1600,1700,……),只有能被400除盡的才為閏年,這樣,400年中只有97個閏年,比原來減少三個,使歷年平均長度為365.2425日,更接近于回歸年的長度,經過這樣修改的儒略歷叫格里高利歷,亦稱格里歷,格里歷二十世紀初為全世界普遍采用,所以又叫公歷,
如何確定一個給定的日期是星期幾呢?
設變數year、month和day分別表示給定日期的年、月和日,由于一個星期有7天,因此,如果我們知道該年的元旦是星期幾(設為week),那么該日期是星期幾就可以確定了,計算公式為:(week+d-1)%7,0代表星期日,其中d為給定日期是當年的第幾天,
怎樣求年號為year這年的元旦是星期幾呢?用一個簡單公式即可計算出來,
設公元 1 年 1月 1日 為星期一,
我們知道一年有365天(當然閏年會有366天,先不管了),每7天1周,365%7=1,即若不考慮閏年,則每年的元旦是星期幾應該是上一年元旦星期幾的后一天,
由于 1 年元旦是星期一,因此 2年元旦星期二,3年元旦星期三,4年元旦星期四,…即
week =(year)%7,
由于閏年的存在會在2月多一天,因此,閏年的下一年元旦星期幾應再加1,即5年為星期六(不是星期五,因為 4年是閏年),因此需要知道前year-1年中有多少個閏年,閏年的規則簡述就是每4年一個閏年,每100年不是閏年,每400年又是閏年,按集合包含與容斥規則,閏年個數有 (year-1)/4 - (year-1)/100 + (year-1)/400,
因此,已知年號year,就可以根據year計算出該年元旦是星期幾,計算公式如下:
week=[ year+(year-1)/4-(year-1)/100+(year-1)/400]%7;
需要說明的是,對于公元歷任一年,這個公式不一定成立,因為由前面的介紹,公元歷在歷史上也不斷調整過,但對于現行的公歷,這一公式是可以正確確定某年元旦是星期幾的,
例如,year=2001,week=(2001+(2001-1)/4-(2001-1)/100+(2001-1)/400)%7
=(2001+500-20+5)%7=1
即2001年元旦是星期一,正好符合,
確定了每年元旦是星期幾后,對之后的年份進行窮舉,找到一個最近的日期,其星期相同即可,不考慮閏年的話,若某兩年的元旦星期相同,則兩年相同的日子的星期也相同;若考慮閏年,則對2月份以后的日子進行閏年處理,
(2)源程式,
#include <stdio.h>
bool isLeap(int year)
{
if (year%4==0 && year%100!=0 || year%400==0)
return true;
else
return false;
}
int main()
{
int year,month,day,t,week1,week2,i;
scanf("%d",&t);
while(t--)
{
scanf("%d-%d-%d",&year,&month,&day);
week1=(year+(year-1)/4-(year-1)/100+(year-1)/400)%7;
for (i=year+1;i<=9999;i++)
{
if (month==2&&day==29&&!isLeap(i))
continue;
week2=(i+(i-1)/4-(i-1)/100+(i-1)/400)%7;
if(month>2)
{
if (isLeap(year) && ! isLeap(i))
week2=(week2-1+7)%7;
if (!isLeap(year) && isLeap(i))
week2=(week2+1)%7;
}
if (week1==week2)
{
printf("%d\n",i);
break;
}
}
}
return 0;
}
71-2 第N個閏年
問題描述
給定一個表示起始年份的正整數Y和一個正整數N,你的任務是求出從Y年開始的第N個閏年,
注:如果Y年是閏年,那么第一個閏年就是Y年,
輸入
輸入包含幾個測驗用例,輸入的第一行是一個整數T,它是測驗用例的數量,
每個測驗用例包含兩個正整數Y和N(1<=N<=10000),
輸出
對于每個測驗用例,您應該輸出從Y年開始的第N個閏年,
輸入樣例
3
2005 25
1855 12
2004 10000
輸出樣例
2108
1904
43236
(1)編程思路,
撰寫函式int leapyear(int year)判斷year年是否是閏年,為求從Y年開始的第N個閏年,進行簡單的回圈處理即可,
(2)源程式,
#include <stdio.h>
int leapyear(int year)
{
if (year%4==0 && year%100!=0 || year%400==0)
return 1;
else
return 0;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int year,n;
scanf("%d%d",&year,&n);
while (leapyear(year)==0) year++;
int cnt=1;
while (cnt<n)
{
year+=4;
if (leapyear(year)==1) cnt++;
}
printf("%d\n",year);
}
return 0;
}
71-3 回文日期
問題描述
在日常生活中,通過年、月、日這三個要素可以表示出一個唯一確定的日期,
小明習慣用8位數字表示一個日期,其中,前4位代表年份,接下來2位代表月份,最后2位代表日期,顯然:一個日期只有一種表示方法,而兩個不同的日期的表示方法不會相同,
小明認為,一個日期是回文的,當且僅當表示這個日期的8位數字是回文的,現在,小明想知道:在他指定的兩個日期之間包含這兩個日期本身,有多少個真實存在的日期是回文的,
一個8位數字是回文的,當且僅當對于所有的i (1≤i≤8)從左向右數的第i個數字和第9?i個數字(即從右向左數的第i個數字)是相同的,
例如:
?對于2016年11月19日,用8位數字20161119表示,它不是回文的,
?對于2010年1月2日,用8位數字20100102表示,它是回文的,
?對于2010年10月2日,用8位數字20101002表示,它不是回文的,
每一年中都有12個月份:
其中,1,3,5,7,8,10,12月每個月有31天;4,6,9,11月每個月有30天;而對于2月,閏年時有29天,平年時有28天,
輸入
兩行,每行包括一個8位數字,
第一行表示小明指定的起始日期date 1,
第二行表示小明指定的終止日期date 2,
輸入資料保證都是真實存在的日期,且年份部分一定為4位數字,且首位數字不為0,
保證date1 —定不晚于date2,
輸出
一個整數,表示在date1和date2之間,有多少個日期是回文的,
輸入樣例
20000101
20101231
輸出樣例
2
(1)編程思路,
采用字串輸入兩個給定的日期date1和date2,然后分離出這兩個日期的年份year1和year2,由于一年中最多只可能有一個回文日期,例如,若年份為abcd,則該年的回文日期可能為abcddcba,若dc在01~12之間,bc在01~XX(XX為dc月最多的天數),則abcddcba才是合法的回文日期,
因此,對year1和year2之間的年份進行窮舉,對每個列舉到的年份,判斷該年可能的回文日期是否合法,同時對于第year1年,可能的回文日期不能小于date1,第year2年,可能的回文日期不能大于date2,條件均滿足,則是一個回文日期,計數,
(2)源程式,
#include <stdio.h>
int main()
{
int table[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
char date1[9],date2[9];
scanf("%s%s",date1,date2);
int year1=0,year2=0,i;
int beginmd=0,endmd=0;
for (i=0;i<4;i++)
{
year1=year1*10+date1[i]-'0';
year2=year2*10+date2[i]-'0';
beginmd=beginmd*10+date1[i+4]-'0';
endmd=endmd*10+date2[i+4]-'0';
}
int cnt=0;
for (i=year1;i<=year2;i++)
{
if ((i%4==0 && i%100!=0) || i%400==0)
table[2]=29;
else
table[2]=28;
int month=(i%10)*10+(i/10)%10;
if (month<1 || month>12) continue;
int day=i/1000+((i/100)%10)*10;
if (day<1 || day>table[month]) continue;
if (i==year1 && month*100+day<beginmd) continue;
if (i==year2 && month*100+day>endmd) continue;
cnt++;
}
printf("%d\n", cnt);
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/438605.html
標籤:C
上一篇:C++ struct和class
