南理工机试日期计算解答

笔者在复习考研,今天无意中看到了南理工2019考研机试题,其中第一题是:已知2000年1月1日是星期六,给定天数n,问n天后是几几年几月几日星期几.按南理工往年命题风格,机试第一题通常是水题或签到题,但令人意外的是今年第一题比较难,难在细节处理繁琐复杂,思考问题时容易迷失方向,即便找到解题方法,编码时也容易出错。
这个问题笔者看到后花费1小时40分钟才完成思考和编码,这不包括调试的时间,南理工机试考试时间也就2个半小时,笔者承认,如果笔者自己上考场,第一题绝对做不出来或做错,不得不承认今年机试题难度有点大
现在给出解答,以下代码涉及5个函数
1:getDaysOfMonth 该函数接受年year和月month,返回month 月的天数
2:getDaysOfYear 该函数接受年year,返回该年的天数
3:calculateYearAndSurplusNumberOfDays 该函数接受年year和相对于该年一月一日的正偏移天数num_of_days,返回从年year一月一日算起num_of_days天后的日期date所在的年份(返回的pair的first成员)和date日期相对于该年份一月一日的正偏移天数(返回的pair的second成员)
4:calculateMonthAndSurplusNumberOfDays 该函数接受年year,月month,和相对于year年month月一号的正偏移天数num_of_days,返回从年year,month月一号算起num_of_days天后的日期date所在year年内的月份(返回的tuple的第二成员)以及date相对于该月份一号的正偏移天数(返回的tuple的第三成员),同时返回true(返回的tuple的第一成员).如果从年year,month月一号算起num_of_days天后的日期date所在年份超出year,则返回下一年year+1(返回的tuple的第二成员),和date超出year的正偏移天数(返回的tuple的第三成员),同时返回false(返回的tuple的第一成员)
5:calculateDayInMonth 该函数接受年year, 月month,日day和相对于year年, month月,day日的正偏移天数num_of_days,如果从年year, 月month,日day算起num_of_days后的日期date仍在月month内,返回date在month内的日数(返回的pair的second成员)和true(返回的pair的first成员)。否则返回date相对于month的下一个月一号的正偏移天数(返回的pair的second成员)和false(返回的pair的first成员)
主函数的执行逻辑是若已知year年,month月,day日星期数是week_count,偏移天数after_num_of_days
先调用calculateDayInMonth函数,若返回值包含true,则从year年,month月,day日算起after_num_of_days后的日期date年数就为year,月数为month,返回的天数就是month下的天数
否则令newyear为month月后一月所在年,new_month为month后一月,以new_year,new_month,和date相对于newmonth一号的偏移天数调用函数calculateMonthAndSurplusNumberOfDays,若返回值包含true,则date年数即为new_year,返回的月数即为date的月数
再以new_year,date的月数和date相对于该月数的偏移天数调用calculateDayInMonth算得date所在的天数
否则以calculateMonthAndSurplusNumberOfDays返回的年数和date相对于该年的偏移天数调用calculateYearAndSurplusNumberOfDays得到date所在年数year和date相对于year一月一号的偏移天数,该偏移天数小于等于year的总天数,再用year和date相对于year一月一号的偏移天数调用以及1月调用calculateMonthAndSurplusNumberOfDays得到date所在月数month和相对于month月一号的月内偏移天数(它小于等于month的总天数)。最后用year,month,一号和date相对于month月一号的月内偏移天数调用calculateDayInMonth算出date的天数day
最后处理的是星期数,如果题目所给星期数是星期天,则week_count为0,如果是星期一到星期六则week_count为对应数字,然后将week_count加上after_num_of_days,求出相加后得到的数除以7的余数,将余数简单转换即得星期数
c++代码如下:

#include <utility>
#include <tuple>
#include <iostream>

using namespace std;

int getDaysOfMonth(long long year, int month)
{
	if (month == 2)
	{
		if (year % 400 == 0 || year % 4 == 0 && year % 100 != 0)
		{
				return 29;
		}
		else
		{
				return 28;
		}
	}

	if (month == 4 || month == 6 || month == 9 || month == 11)
		return 30;
	else
		return 31;
}

int getDaysOfYear(long long year)
{
	if (year % 400 == 0 || year % 4 == 0 && year % 100 != 0)
		return 366;
	else
		return 365;
}

pair<long long, long long> calculateYearAndSurplusNumberOfDays(long long year, long long num_of_days)
{
	for (long long y = year; ; ++y)
	{
		int days = getDaysOfYear(year);
		if (num_of_days <= days)
		{
			return { y, num_of_days };
		}
		num_of_days = num_of_days - days;
	}
}

/*pair<long long, long long> calculateYearAndSurplusNumberOfDays(long long year, long long num_of_days)
{
	long long days_offset = 1;
	for (long long y = year; ; ++y)
	{
		int days = getDaysOfYear(year);
		if (num_of_days < days_offset + days)
		{
			return { y, num_of_days - days_offset + 1 };
		}
		days_offset = days_offset + days;
	}
}
这里是num_of_days的第二种实现方法*/

tuple<bool, long long, long long> calculateMonthAndSurplusNumberOfDays(long long year, int month, long long num_of_days)
{
	int days_offset = 1;
	for (int i = month; i <= 12; ++i)
	{
		int days = getDaysOfMonth(year, i);
		if (num_of_days < days_offset + days)
		{
			return { true, i, num_of_days - days_offset + 1 };
		}
		days_offset = days_offset + days;
	}

	return { false, year + 1, num_of_days - days_offset + 1 };
}

pair<bool, long long> calculateDayInMonth(long long year, int month, int day, long long num_of_days)
{
	int days = getDaysOfMonth(year, month);
	if (num_of_days > days - day)
	{
		return { false, num_of_days - (days - day) };
	}
	else
	{
		return { true, day + num_of_days };
	}
}

int main()
{
	int year = 2000;
	int month = 1;
	int day = 1;
	short week_count = 6;
	long long after_num_of_days = 1000;

	auto temp = calculateDayInMonth(year, month, day, after_num_of_days);
	if (temp.first)
	{
		cout << year << "年" << month << "月" << temp.second << "日" << endl;
	}
	else
	{
		int new_year;
		int new_month;
		if (month == 12)
		{
			new_year = year + 1;
			new_month = 1;
		}
		else
		{
			new_year = year;
			new_month = month + 1;
		}
		auto p = calculateMonthAndSurplusNumberOfDays(new_year, new_month, temp.second);
		if (get<0>(p))
		{
			cout << new_year << "年" << get<1>(p) << "月" << calculateDayInMonth(new_year, get<1>(p), 1, get<2>(p) - 1).second << "日";
		}
		else
		{
			auto s = calculateYearAndSurplusNumberOfDays(get<1>(p), get<2>(p));
			auto v = calculateMonthAndSurplusNumberOfDays(s.first, 1, s.second);
			cout << s.first << "年" << get<1>(v) << "月" << calculateDayInMonth(s.first, get<1>(v), 1, get<2>(v) - 1).second << "日";
		}
	}
	week_count = (week_count + after_num_of_days) % 7;
	if (week_count == 0)
	{
		cout << "星期天" << endl;
	}
	else
	{
		cout << "星期" << week_count << endl;
	}

}

PS:这里简单讨论一下与上题无关的2019南理工机试第6题。即若有n个商品,编号1,2,—n,第i个商品数量为Ni,购买所需积分为Si,Ni和Si均为正数,问若已有积分C,则用积分C能买到的商品的积分总和最大是多少?
这题就是背包问题的变形,DP动态规划即可,设a[i,j]表示用积分j购买第1,2,–,i个物品时购买的物品的最大总积分,那么显然有状态转移方程a[i, j] = max{a[i-1, j], max{a[i-1, j-xSi]+xSi 1<= x <= Ni j-x*Si>=0}} 写出状态转移方程后编码就很容易了,最后代码也很简单,这里就不贴了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值