二哥想知道在一段时期内,一共有多少个交易日。期货交易日的限定如下:
周六、周日不能交易
元旦期间(1月1日)不能交易
五一劳动节期间(5月1日至3日)不能交易
十一国庆节期间(10月1日至7日)不能交易
没有在上述要求中提到的日期均可交易
第一行有一个整数n,表示一共有n组数据。
每组数据都有一行,是两个用空格分开的日期,分别为开始日期和结束日期。日期格式为YYYY-MM-DD(比如2010-11-11);数据保证开始日期不晚于结束日期。
对于所有数据:n≤365
对于30%的数据:日期范围从2010-11-23至2012-12-21
对于70%的数据:日期范围从1900-01-01至9999-12-31
输出共n行,每行一个整数,对应于一组数据。
每组数据需要输出在指定日期区间内,共有多少个交易日;区间的开始和结束日期也算在内(如果是交易日的话)。
4 2010-11-18 2010-11-20 2010-01-01 2010-01-01 2010-05-01 2010-05-03 2010-10-01 2010-10-07
2 0 0 0
这个题目主要考虑日期方面的一些算法,这里假设左边的日期为date1,右边的日期为date2,由于题目保证date1在date2之前,所以我们可以首先计算出date2-date1,如何求出date2-date1?
这里首先介绍日期方面的第一个算法,大家如果有使用过mktime函数的话可能会了解,mktime函数在linux代码中的实现如下所示:
static inline unsigned long
mktime (unsigned int year, unsigned int mon,
unsigned int day, unsigned int hour,
unsigned int min, unsigned int sec)
{
if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
mon += 12; /* Puts Feb last since it has leap day */
year -= 1;
}
return (((
(unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day + year*365 - 719499
)*24 + hour /* now have hours */
)*60 + min /* now have minutes */
)*60 + sec; /* finally seconds */
在http://blog.csdn.net/axx1611/article/details/1792827上对这个进行了详细的解析,我们可以通过
year/4 - year/100 + year/400 + 367*mon/12 + day + year*365 - 719499求解一个date相对于1年1月1日的天数,这里我们并不关注绝对相差值,只需要知道日期之间的相对差,所以719499是不必要的,只需要通过year/4 - year/100 + year/400 + 367*mon/12 + day + year*365求解即可,那么我们可以实现date之间的日子数,下面一个问题是如何排除那些节日和周末?
那么很值得讨论的一个问题是如何确定一天到底是星期几?这里有一个和上述差不多的算法,
int dayofweek(int year,int month,int day)
{
static int t[]={0,3,2,5,0,3,5,1,4,6,2,4};
year-=month<3;
int ans=(year+year/4-year/100+year/400+t[month-1]+day)%7;
if(ans==0) ans=7;
return ans;
}
对于date1到date2,假设date1为星期k,date2为星期t,date1到date2之间周一到周日的循环数为cycle,则有(7-k+1)+7*cycle+t=date2-date1,由此可以确定date1到date2之间的星期日和星期六数目,但是这里面可能有一些日子既是周末也是节日,那么我们需要计算重复的日子,对于date1到date2这些年份的所有节日都求出和1年1月1日的相差,放在一个vector里面,那么对于那些在date1到date2之间的节日计算其是否为星期六和星期日。
#include <iostream>
#include <vector>
using namespace std;
struct date
{
int year;
int month;
int day;
};
int dayofweek(int year,int month,int day)
{
static int t[]={0,3,2,5,0,3,5,1,4,6,2,4};
year-=month<3;
int ans=(year+year/4-year/100+year/400+t[month-1]+day)%7;
if(ans==0) ans=7;
return ans;
}
int days_between_dates(int year,int month,int day)
{
if((month-=2)<=0)
{
year--;
month+=12;
}
return (year/4 - year/100 + year/400 + 367*month/12 +day + year*365);
}
int festivals(int year1,int year2,vector<int>& result)
{
for(int i=year1;i<=year2;i++)
{
result.push_back(days_between_dates(i,1,1));
result.push_back(days_between_dates(i,5,1));
result.push_back(days_between_dates(i,5,2));
result.push_back(days_between_dates(i,5,3));
result.push_back(days_between_dates(i,10,1));
result.push_back(days_between_dates(i,10,2));
result.push_back(days_between_dates(i,10,3));
result.push_back(days_between_dates(i,10,4));
result.push_back(days_between_dates(i,10,5));
result.push_back(days_between_dates(i,10,6));
result.push_back(days_between_dates(i,10,7));
}
return 0;
}
int main()
{
int n;
char a;
cin>>n;
date tp1;
date tp2;
for(int i=0;i<n;i++)
{
int total=0;
vector<int> res;
cin>>tp1.year>>a>>tp1.month>>a>>tp1.day;
cin>>tp2.year>>a>>tp2.month>>a>>tp2.day;
festivals(tp1.year,tp2.year,res);
int ans1=dayofweek(tp1.year,tp1.month,tp1.day);
int ans2=dayofweek(tp2.year,tp2.month,tp2.day);
int left_year=days_between_dates(tp1.year,tp1.month,tp1.day);
int right_year=days_between_dates(tp2.year,tp2.month,tp2.day);
int cycle=(right_year-left_year-7+ans1-ans2)/7;
total+=(right_year-left_year+1)-cycle*2;
if(ans1<=6) total=total-2;
else total=total-1;
if(ans2>=6) total=total-(ans2-5);
int i1=-1,j1=res.size();
while(res[++i1]<left_year);
while(res[--j1]>right_year);
total=total-(j1-i1+1);
for(int t=i1;t<=j1;t++)
{
int tp=(res[t]-left_year+ans1)%7;
if(tp==0||tp==6) total++;
}
cout<<total<<endl;
}
return 0;
}
由于问题前后改了很多遍,代码可能显得混乱。