Intersecting Dates 日期问题

问题描述

研究组正在开发一个计算机程序,这个程序会从一个服务获得历史股票市场价格数据。而这个服务每提供一天的股市数据,都要收取一个固定的费用。这个研究组检查了过去请求的价格数据,发现有着大量的重复,也就浪费了不少的研究经费。所以新的程序需要维护一个表来保存研究组成员曾经请求过的所有价格数据。当需要一段新的价格数据时,只有曾经没有请求过的会从服务获得,从而减少研究开销。

你的任务是完成一个程序来判断是否需要从服务请求新的价格数据。程序的输入包括所有过去请求过的价格数据的日期区间,和现在需要的日期区间。这个程序需要输出必须从服务获得的数据的日期区间。

输入格式

有多组测试数据。每组测试数据以两个非负整数 NX 和 NR 开始,(0 <= NX, NR <= 100)。NX 是已获取过的日期区间数,NR 是现在需要的日期区间数。接下去的输入是 NX + NR 对日期。每对日期的第一个日期都一定小于等于第二个日期。前面的 NX 对日期表示已获取过的日期区间,后 NR 对表示现在需要的日期区间。

最后一组测试数据后,以两个零终结输入。

每个输入日期都会以 YYYYMMDD 的形式给定。YYYY 是年份(1700 到 2100),MM 代表月份(01 到 12),而 DD 表示日(在给定的年份、月份允许的范围内)。月份 04、06、09、11 有 30 天,而 01、03、05、07、08、10、12 有 31 天,除了闰年,02 月有 28 天,而闰年则为 29 天。如果年份能被 4 整除并且不是一个世纪年(100 的倍数),或者是 400 的倍数时,可以判定这年是闰年。

输出格式

对于每组测试数据,首先显示测试数据编号(1,2,…),紧接着是一个表,内容是必须从服务获得数据的日期区间,每行一个。以下面样例显示的美国日期格式输出。当没有价格数据需要从服务获取时明确地说明(如样例)。如果两个日期区间是连续的或者重叠的,将它们合并为一个。如果一个日期区间里只有一天,只需将其显示出来,而不是显示包括两个相同日期的日期区间。以日期顺序显示日期区间,从最早的日期开始。

思路

将每一个日期转换成距离1700年1月1日的天数,用一个bool类型的数组用来将已经拥有的日期区间和需要查询的日期区间进行涂色,然后从需要查询的最小日期开始遍历数组,记录需要查询的日期区间的两个端点,转化为日期类型打印出来,注意一定要从最小的日期开始遍历而不能从1开始,因为会超时,需要注意的细节就是闰年的二月有29天,在对日期进行转化时要多多注意

代码


```cpp
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <cstdio>
using namespace std;
int nx, nr, l1, r1;
const int Max = 1e8;
bool have[Max], need[Max];
int month[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool judge(int yy) {
 if((yy % 4 == 0 && yy % 100) || yy % 400 == 0)
 return true;
 else
 return false;
}
struct date{
 int yy,mm,dd;
 bool operator==(const date &tmp) const{return yy==tmp.yy && mm == tmp.mm && dd == tmp.dd;};
};
int convertnum(date dt) {       //转化为数字
 int yy = dt.yy, mm = dt.mm, dd = dt.dd;
 int sum = 0;
    for(int i = 1700; i < yy; i++) {
     if(judge(i))
     sum += 366;
     else 
     sum += 365;
 }
 for(int i = 1; i < mm; i++)
 sum += month[i];
 sum += dd;
 if(judge(yy) && mm > 2)
 sum ++;
 return sum;
}
date convertdate(int num) {     //转化为日期类型
  date ans;
  int yy = 1700, mm = 1, dd;
  while((num > 366 && judge(yy)) || (num > 365 && judge(yy) == false)) {
   if(judge(yy))
   num -= 366;
   else 
   num -= 365;
   yy ++;
  }
  if(judge(yy)) month[2] = 29;
  while(num > month[mm]){
   num -= month[mm];
   mm ++;
  }
  dd = num;
  ans.yy = yy;
  ans.mm = mm;
  ans.dd = dd;  
  month[2] = 28; //此处 要把month[2]值置回28
  return ans;
}
void draw(bool *a ,date begin, date end, int &l1, int &l2) { //区间涂色
   l1 = convertnum(begin);
   l2 = convertnum(end);
  for(int i = l1; i <= l2; i++)
  a[i] = true;
  return;
}
date change(string s) {
 date ans;
 ans.yy = (s[0] - '0')*1000 + (s[1] - '0')*100 + (s[2] - '0')*10 + s[3] - '0';
 ans.mm = (s[4] - '0')*10 + s[5] - '0';
 ans.dd = (s[6] - '0')*10 + s[7] - '0';
 return ans;
}
int main() {
 int k = 1;
 //freopen("E:\\input7.txt", "r", stdin);
 while(scanf("%d%d", &nx, &nr)) {
  if(nx == 0 && nr == 0)
  break;
  bool flag = false;
  memset(need, false, sizeof(need));
  memset(have, false, sizeof(have));
  month[2] = 28;
     date begin, end;
     string time;
     int l, r;
  for(int i = 1; i <= nx; i++) {
   cin >> time;
   begin = change(time);
   cin >> time;
   end = change(time);
   draw(have, begin, end, l, r);
  }
  l1 = Max, r1 = 0;
  for(int i = 1; i <= nr; i++) {
   cin >> time;
   begin = change(time);
   cin >> time;
   end = change(time);
   draw(need, begin, end, l, r);
   if(l1 > l) l1 = l;
   if(r1 < r) r1 = r;
  }
  int sum = 0;
  printf("Case %d:\n", k++);
  int l2;
  for(l1 ; l1 <= r1; ) {
   if(need[l1] == false || have[l1] == true) {
    l1 ++;
    continue;
   }
   flag = true;
   for(l2 = l1; need[l2] == true && have[l2] == false; l2++);
      begin = convertdate(l1);
      end = convertdate(l2 - 1);
      if(begin == end)
      printf("    %d/%d/%d\n", begin.mm, begin.dd, begin.yy);
      else
      printf("    %d/%d/%d to %d/%d/%d\n", begin.mm, begin.dd, begin.yy, end.mm, end.dd, end.yy);
      l1 = l2;
  }
  if(flag == false)
  printf("    No additional quotes are required.\n");
  printf("\n");
 }
 return 0;
}
``

找了三个多小时的错误, 发现不需要查询的情况输出把四个空格打在了引号外面,还有就是执行日期转化函数的时候没有把month[2] 置回 28天 ,泪崩。。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值