杭电OJ 1006题 题目链接:点击打开链接
本题思路:最开始尝试使用枚举的方法,以s为单位进行遍历时发现结果的精度不够,以ms为单位时可以满足精度要求,但是会超时。最终解题思路如下:
(1)秒针1s走6度,分针1s走0.1度,时针1s走1/120度。所以分针秒针每秒的度数差为5.9°,时针分针每秒的度数差为11/120°,时针秒针每秒的度数差为719/120°。
(2)从00:00:00开始考虑,此时分秒针都指向最上方12点方向。12个小时之后,时分秒针再次都指向最上方,完成一个周期,所以只需要计算12小时内三个指针happy的累计“秒数”,然后除以12小时的总秒数就得到了结果(12小时和24小时的结果是一样的~)。
(3)从00:00:00开始考虑,根据上述条件,可以分别计算出时针分针、时针秒针、分针秒针在12小时中,每一次满足happy条件的起止时间,使用数组保存。
(4)需要注意的是,为了满足happy的条件,既需要判断顺时针夹角1是否满足条件,也需要判断该夹角1的对顶角2是否满足条件。因为夹角1和夹角2都是这两个指针构成的角度。
(5)使用数轴来表示时间(使用数轴画一画会更容易理解),根据数组中保存的值寻找交集,则可以找到时针分针秒针都happy的时间段。
本题AC参考代码:
import java.io.BufferedInputStream;
import java.text.DecimalFormat;
import java.util.Scanner;
public class Main {
private static double max(double a, double b, double c) {
a = a > b ? a : b; // a的值修改为a,b之中较大的那个
a = a > c ? a : c; // a的值修改为a,c之中较大的那个(参与计算的a已经是a,b中较大的数,所以最终的a是a,b,c中最大的)
return a;
}
private static double min(double a, double b, double c) {
a = a < b ? a : b;
a = a < c ? a : c;
return a;
}
public static void main(String[] args) {
Scanner cin = new Scanner(new BufferedInputStream(System.in));
int total = 12 * 60 * 60;
// 记录两两指针之间的起止时间
// 用于记录分针秒针happy起止时间的数组. bms中的b表示begin,ems中的e表示end
// 数组大小708,是因为12小时内分针秒针共重合708次,所以happy的起止次数也为708次
//(重合708次是事先计算好的)
// 为了防止数组溢出,数组大小设置为709
double[] bms = new double[709];
double[] ems = new double[709];
// 用于记录时针分针happy起止时间的数组.
// 时针分针12小时内共重合11次
double[] bhm = new double[12];
double[] ehm = new double[12];
// 用于记录时针秒针happy起止时间的数组.
// 时针分针12小时内共重合719次
double[] bhs = new double[720];
double[] ehs = new double[720];
// 分针秒针每秒相差的度数
double dms = 5.9;
// 时针分针每秒的度数差
double dhm = 11.0 / 120;
// 时针秒针每秒的度数差
double dhs = 719.0 / 120;
double d = cin.nextDouble();
while (d != -1) {
// 12小时内,happy时间差累计
double count = 0;
// 计算并填充各个数组的值
bms[0] = d / dms; // 分针秒针第一次happy的起始时间(顺时针夹角,开始满足条件)
ems[0] = (360.0 - d) / dms; // 分针秒针第一次happy的结束时间(顺时针夹角的对顶角,开始不满足条件)
for (int i = 1; i < 709; i++) {
// 分针秒针第i次重合之后,满足happy条件的开始时间
bms[i] = (360.0 * i) / dms + bms[0]; // (360*i)/dms:为分针秒针第i次重合的时间
ems[i] = (360.0 * i) / dms + ems[0];
}
// 计算bhm、ehm、 bhs、 ehs的道理和上述相同
bhm[0] = d / dhm;
ehm[0] = (360.0 - d) / dhm;
for (int i = 1; i < 12; i++) {
bhm[i] = (360.0 * i) / dhm + bhm[0];
ehm[i] = (360.0 * i) / dhm + ehm[0];
}
bhs[0] = d / dhs;
ehs[0] = (360.0 - d) / dhs;
for (int i = 1; i < 720; i++) {
bhs[i] = (360.0 * i) / dhs + bhs[0];
ehs[i] = (360.0 * i) / dhs + ehs[0];
}
//i、j、k分别用来记录bhs[i], bms[j], bhm[k]数组的当前访问位置
int i = 0;
int j = 0;
int k = 0;
//时分秒针满足happy条件的开始时间和结束时间
double begin = 0.0;
double end = 0.0;
while (begin <= total && end <= total) {
// 起始时间取较大值
begin = max(bhs[i], bms[j], bhm[k]);
// 结束时间取较小值
end = min(ehs[i], ems[j], ehm[k]);
//在一次循环中,只会改变i、j、k中的某一个值,将相对最后的那一个向前移动。。。
//不太好解释,画画数轴会比较好理解
if (end == ehs[i]) {
i++;
}
if (end == ems[j]) {
j++;
}
if (end == ehm[k]) {
k++;
}
if (end > begin && end <= total) {
count += (end - begin);
}
}
// 保留三位小数输出
DecimalFormat formatter = new DecimalFormat("#0.000");
double result = ((count + 0.00) / total) * 100;
System.out.println(formatter.format(result));
d = cin.nextDouble();
}
cin.close();
}
}
欢迎评论讨论指正,不喜勿喷。