【问题标题】:Number theory modular arithmetic how to account for adjustments数论模算术如何解释调整
【发布时间】:2018-04-11 16:21:31
【问题描述】:

我不确定我的解决方案是否合理(ans. 171) - Project Euler Q.19,因为我很难理解模运算,并且不确定我的方法是否正确。 ..我在尝试获得将 0 作为键而不是 1 到星期一以在哈希表中引用的等效性时遇到了麻烦。问题是;

  • 1900 年 1 月 1 日是星期一。
  • 30 天有九月、四月、六月和十一月。其余的都有三十一,仅存二月,二月有二十八,雨
    或闪耀。闰年是二十九岁。
  • 闰年出现在任何能被 4 整除的年份,但不会出现在一个世纪,除非它能被 400 整除。

在第 20 个月的第一天有多少个星期天 世纪(1901 年 1 月 1 日至 2000 年 12 月 31 日)?

所以我所做的是将天数总和从 1 开始(参考哈希表中的天数)并在找到星期日的总和后减去 1,因为当总天数可被 3 整除时,将其除以 0 会导致问题和 6(3:星期三,6:星期日)。我怎么能通过使用 0 作为星期一的参考来做到这一点?

import java.util.*;

public class p19 {

    public static void main(String[] args) {

        Hashtable<Integer, String> days = new Hashtable<Integer, String>();
        days.put(1, "Monday");
        days.put(2, "Tuesday");
        days.put(3, "Wednesday");
        days.put(4, "Thursday");
        days.put(5, "Friday");
        days.put(6, "Saturday");
        days.put(7, "Sunday");

        Hashtable<Integer, String> months = new Hashtable<Integer, String>();
        months.put(1, "January");
        months.put(2, "February");
        months.put(3, "March");
        months.put(4, "April");
        months.put(5, "May");
        months.put(6, "June");
        months.put(7, "July");
        months.put(8, "August");
        months.put(9, "September");
        months.put(10, "October");
        months.put(11, "November");
        months.put(12, "December");

        int min, max;
        min = 1900;
        max = 2000;

        String[][] arr = new String[12 * (max - min + 1)][];

        // Total days starts at 1 to make modular arithmetic easier when accounting for days 
        // (i.e., 1 Monday, 2 Tuesday, etc.) and since the first day, hence, 0th day on 1 Jan 1900 is Monday.
        for (int year = min, index = 0, totalDays = 1; year <= max; year++) {

            for (int month = 1; month <= 12; month++, index++) {

                arr[index] = new String[numberOfDays(month,year)];

                int sum = 1;

                System.out.println(months.get(new Integer(month)) + " " + year);

                for (int day = 1; day <= numberOfDays(month, year); day++, totalDays++) {

                    if (totalDays % 7 == 0) {

                        arr[index][day - 1] = days.get(new Integer((totalDays % 7 + 7) % 365));                         
                    }
                    else {

                        arr[index][day - 1] = days.get(new Integer((totalDays % 7) % 365));                         
                    }

                    if (sum > 7) {

                        System.out.println();

                        sum = 1;
                    }

                    System.out.print(totalDays + ":= " + arr[index][day - 1] + ", " + day + " | ");

                    sum++;
                }

                System.out.println("\n");
            }
        }

        int count = 0;

        for (int i = 1; i < arr.length; i++) {

            if (arr[i][0] == "Sunday") {

                count++;
            }
        }
        // Subtract 1 from count since the total days were overstated by 1 before inititallizing array
        System.out.println("Number of Sundays that fell on the first of the month from: 1/Jan/1901 - 31/Dec/2000: " + (count - 1));
    }

    public static int numberOfDays (int month, int year) {

        int days = 0;

        switch (month) {
            case 7: 
            case 4: 
            case 6: 
            case 11:
                days = 30;
                break;
            case 2:
                if (isLeapYear(year)) {
                    days = 29;
                }
                else {
                    days = 28;
                }
                break;
            default: days = 31;
                break;   
        }

        return days;
    }

    public static boolean isLeapYear(int year) {

        return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
    }
} 

【问题讨论】:

  • 我不得不承认我不明白你的做法。恕我直言,您可以选择 1901 年的第一个星期日并在每个日期上加上 +7,然后检查日期是否为 YYYY-MM-01。或者你从 1901-2000 年,从 1 到 12 月,生成日期 y/m/01 并检查它是否是星期日。所以你试图在没有日期/时间库的情况下解决它。但是为什么你需要月份名称?工作日的名称是什么?在不使用日期/时间库的情况下,为什么要从 1 开始索引天数和月份,而这很难通过模运算得到正确的结果?
  • 顺便说一句。这是一种 shell 方法,但使用日期函数:for x in {0..36525..7}; do date -d "6 Jan 1901 +$x days" | grep "So 1\." ; done | wc -l 171 和这里的另一个方法(在我的语言环境中也是星期天)cnt=0; for y in {1901..2000}; do for m in {1..12}; do dow=$(date -d "$y-$m-01" +%a); if [[ $dow == "So" ]] ; then ((++cnt)); fi; done; done; echo $cnt 结果:171
  • 直到现在我才知道日期/时间库,谢谢。而且我很难想象,所以我制作了一个数组来打印 LOL。
  • 好吧,作为模运算的练习,这不是浪费时间。 Java 日期时间库 (java.util.Date) 引入了一个接口,其中 getMonth 返回 0 表示 1 月,这与其他函数配合得很好,但当然每个人都希望 6 指代 6 月。我想新的替代品避免了这个陷阱,几乎每个初学者都会进入这个陷阱,甚至有经验的程序员偶尔也会进入这个陷阱。 :)
  • 非常感谢,非常感谢!

标签: java math number-theory modular-arithmetic


【解决方案1】:

您的 daysInMonth 检查不正确 - 结果一定是正确的:

switch (month) {
    case 4:
    case 6:
    case 9:
    case 11:
        days = 30;
        break;

程序的其余部分可以简化 - 请注意,开始年份也必须更正,dow 代表 DayOfWeek:

public static void main (String[] args) {

    int count = 0;
    // dow = 2, since 1.1.1901 was a Thuesday (2)
    for (int year = 1901, dow = 2; year <= 2000; ++year)
    {
        for (int month = 1; month <= 12; ++month)
        {
            if (dow == 0) {
                // System.out.println ("Date: " + year + "-" + month);
                ++count;
            }
            dow = (dow + numberOfDays (month, year)) % 7;
        }
    }
    System.out.println ("Number of Sundays that fell on the first of the month from: 1/Jan/1901 - 31/Dec/2000: " + count);
}

【讨论】:

  • 关于逐个错误的声明是错误的。在 println 语句中有 (count-1) :)。
猜你喜欢
  • 2015-01-19
  • 2017-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多