【TopCoder SRM 157 DIV 1】 Salary 解题报告

本来想把原题给贴过来的,后来看到人家有版权保护,在网上搜了一下,好像也没有人在博客中贴过原题,为避免麻烦,就不copy人家原题了。

【题目大意】

公司按照每小时 wage 元给员工发工资,员工上班打卡记录一个时间,下班记录一个时间,时间格式为 "hh:mm:ss"。其中,18:00:00 到 23:59:59 和 00:00:00 到 05:59:59 之间算加班时间,工资为1.5倍。计算工资时,分钟和秒都换算成小时来计算,最终的工资取整数,舍弃后面的小数。

【函数格式】

int howMuch(vector <string> arrival, vector <string> departure, int wage)

【注意】

arrival和departure元素个数一样,且arrival[0]<departure[0]<arrival[1]<departure[1]等等。

【解题思路】

思路不难,只是时间区间判断比较麻烦,有两个时间关键点06:00:00和18:00:00。

【我的代码】

class Salary {
public:
	int compareTime(int hh1, int mm1, int ss1, int hh2, int mm2, int ss2) {
		if (hh1 > hh2 || (hh1 == hh2 && mm1 > mm2) || (hh1 == hh2 && mm1 == mm2 && ss1 > ss2)) {
			return 1;
		}
		if (hh1 < hh2 || (hh1 == hh2 && mm1 < mm2) || (hh1 == hh2 && mm1 == mm2 && ss1 < ss2)) {
			return -1;
		}
		return 0;
	}

	double duringTime(int hh1, int mm1, int ss1, int hh2, int mm2, int ss2) {
		double time = 0;
		if (ss2 >= ss1) {
			time += (ss2 - ss1) / 3600.0;
		} else {
			time += (ss2 + 60 - ss1) / 3600.0;
			mm2 -= 1;
		}
		if (mm2 >= mm1) {
			time += (mm2 - mm1) / 60.0;
		} else {
			time += (mm2 + 60 - mm1) / 60.0;
			hh2 -= 1;
		}
		time += hh2 - hh1;
		return time;
	}

	int howMuch(vector <string> arrival, vector <string> departure, int wage) {
		int beginHour, endHour, beginMinute, endMinute, beginSecond, endSecond;
		stringstream ss;
		double total = 0;
		for (int i = 0; i < arrival.size(); i++) {
			string time1 = arrival[i];
			ss.clear();
			ss << time1.substr(0, 2);
			ss >> beginHour;
			ss.clear();
			ss << time1.substr(3, 2);
			ss >> beginMinute;
			ss.clear();
			ss << time1.substr(6, 2);
			ss >> beginSecond;
			string time2 = departure[i];
			ss.clear();
			ss << time2.substr(0, 2);
			ss >> endHour;
			ss.clear();
			ss << time2.substr(3, 2);
			ss >> endMinute;
			ss.clear();
			ss << time2.substr(6, 2);
			ss >> endSecond;

			if (compareTime(beginHour, beginMinute, beginSecond, 6, 0, 0) < 0) {
				if (compareTime(endHour, endMinute, endSecond, 6, 0, 0) < 0) {

					total += duringTime(beginHour, beginMinute, beginSecond, endHour, endMinute, endSecond) * wage * 1.5;

				} else if (compareTime(endHour, endMinute, endSecond, 6, 0, 0) >= 0
						&& compareTime(endHour, endMinute, endSecond, 18, 0, 0) < 0) {

					total += duringTime(beginHour, beginMinute, beginSecond, 6, 0, 0) * wage * 1.5;
					total += duringTime(6, 0, 0, endHour, endMinute, endSecond) * wage;

				} else if (compareTime(endHour, endMinute, endSecond, 18, 0, 0) >= 0) {

					total += duringTime(beginHour, beginMinute, beginSecond, 6, 0, 0) * wage * 1.5;
					total += duringTime(6, 0, 0, 18, 0, 0) * wage;
					total += duringTime(18, 0, 0, endHour, endMinute, endSecond) * wage * 1.5;
				}
			} else if (compareTime(beginHour, beginMinute, beginSecond, 18, 0, 0) < 0) {
				if (compareTime(endHour, endMinute, endSecond, 18, 0, 0) < 0) {

					total += duringTime(beginHour, beginMinute, beginSecond, endHour, endMinute, endSecond) * wage;

				} else if (compareTime(endHour, endMinute, endSecond, 18, 0, 0) >= 0) {

					total += duringTime(beginHour, beginMinute, beginSecond, 18, 0, 0) * wage;
					total += duringTime(18, 0, 0, endHour, endMinute, endSecond) * wage * 1.5;
				}
			} else {
				total += duringTime(beginHour, beginMinute, beginSecond, endHour, endMinute, endSecond) * wage * 1.5;
			}

		}
		return (int)total;
	}
};

首先是字符串转换成时分秒整数值。两个自定义函数功能分别为:比较两个时间点先后,主要是和两个关键时间点06:00:00和18:00:00比较;计算两个时间点之间的小时数。

然后一大段逻辑判断,判断员工工作时间是不是在00:00:00和06:00:00之间、06:00:00和18:00:00之间、18:00:00和00:00:00之间,还是说跨时间段。

由于基础不好,代码写得比较啰嗦,欢迎大家改进。

【高手代码】

class Salary {
public:
	int howMuch(vector <string> arrival, vector <string> departure, int wage) {
		long long total = 0;
		for(int i = 0; i < arrival.size(); i++) {
			total += calc(departure[i]) - calc(arrival[i]);
		}
		return total * wage / 7200;
	}

	long long calc(string t) {
		for (int i = 0; i < t.size(); i++) {
			if (t[i] == ':') {
				t[i] = ' ';
			}
		}
		stringstream sstream(t);
		int hh, mm, ss;
		sstream >> hh >> mm >> ss;
		int total = 3600 * hh + 60 * mm  + ss;
		long long x = 0;
		for (int i = 0; i < total; i++) {
			if (i >= 0 && i < 6 * 3600) {
				x += 3;
			} else if (i >= 18 * 3600 && i < 24 * 3600) {
				x += 3;
			} else {
				x += 2;
			}
		}
		return x;
	}
};

一眼就可以看出,人家的代码要简洁很多。这个代码的思路是计算24小时的每一秒拿工资的倍数,然后把工作时间的所有秒的倍数累加起来。由于加班时间工资是1.5倍,为计算方便,都乘以2,也就是说正常工作时间是2倍工资,加班时间是3倍工资,最后再除以2。所以代码中返回值处有个除以7200。

【学习点】

1. 关于时间的计算,换算成秒计算比时分秒操作方便;

2. 关于取整,可以先放大倍数,最后再缩小到原来,这样不容易丢失精度。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值