トップページに戻る    次の増井さんの書籍の問題へ    前の増井さんの書籍の問題へ

Q63 カレンダーの最大長方形


C#のソース

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        int Answer = 0;
        for (int Year = 2006; Year <= 2015; Year++) {
            for (int Month = 1; Month <= 12; Month++) {
                int[,] CalendarArr = DeriveCalendarArr(Year, Month);
                int MaxMenseki = DeriveMaxMenseki(CalendarArr);
                Answer += MaxMenseki;
            }
        }
        Console.WriteLine("120ヶ月分の面積の和={0}", Answer);
    }

    //年と月を引数として、カレンダーの2次元配列を返す
    static int[,] DeriveCalendarArr(int pYear, int pMonth)
    {
        //DayOfWeekの値の対応表
        // 0  1  2  3  4  5  6
        //日 月 火 水 木 金 土

        var YokoArrList = new List<int[]>();
        var YokoList = new List<int>();

        DateTime CurrDay = new DateTime(pYear, pMonth, 1);

        //1日の曜日を求める
        int CurrYoubi = (int)CurrDay.DayOfWeek;

        //1日より前は-1とする
        for (int I = 0; I < CurrYoubi; I++) {
            YokoList.Add(-1);
        }

        while (true) {
            if (CurrDay.Month != pMonth) { //対象月でない場合
                YokoList.Add(-1);
            }
            else if (CurrYoubi == 0 || CurrYoubi == 6) { //土日の場合
                YokoList.Add(-1);
            }
            else if (IsSyukujitu(CurrDay)) { //祝日の場合
                YokoList.Add(-1);
            }
            else YokoList.Add(CurrDay.Day);

            CurrDay = CurrDay.AddDays(1);
            CurrYoubi = (int)CurrDay.DayOfWeek;

            if (CurrYoubi == 0) {
                YokoArrList.Add(YokoList.ToArray());
                YokoList.Clear();
                if (CurrDay.Month != pMonth) break;
            }
        }

        int[,] WillReturn = new int[7, YokoArrList.Count];
        for (int Y = 0; Y <= YokoArrList.Count - 1; Y++) {
            for (int X = 0; X <= 6; X++) {
                WillReturn[X, Y] = YokoArrList[Y][X];
            }
        }
        return WillReturn;
    }

    //祝日かを返す
    static bool IsSyukujitu(DateTime pDate)
    {
        string[] StrArr =
        {"2006/01/01","2006/01/02","2006/01/09","2006/02/11","2006/03/21","2006/04/29",
         "2006/05/03","2006/05/04","2006/05/05","2006/07/17","2006/09/18","2006/09/23",
         "2006/10/09","2006/11/03","2006/11/23","2006/12/23","2007/01/01","2007/01/08",
         "2007/02/11","2007/02/12","2007/03/21","2007/04/29","2007/04/30","2007/05/03",
         "2007/05/04","2007/05/05","2007/07/16","2007/09/17","2007/09/23","2007/09/24",
         "2007/10/08","2007/11/03","2007/11/23","2007/12/23","2007/12/24","2008/01/01",
         "2008/01/14","2008/02/11","2008/03/20","2008/04/29","2008/05/03","2008/05/04",
         "2008/05/05","2008/05/06","2008/07/21","2008/09/15","2008/09/23","2008/10/13",
         "2008/11/03","2008/11/23","2008/11/24","2008/12/23","2009/01/01","2009/01/12",
         "2009/02/11","2009/03/20","2009/04/29","2009/05/03","2009/05/04","2009/05/05",
         "2009/05/06","2009/07/20","2009/09/21","2009/09/22","2009/09/23","2009/10/12",
         "2009/11/03","2009/11/23","2009/12/23","2010/01/01","2010/01/11","2010/02/11",
         "2010/03/21","2010/03/22","2010/04/29","2010/05/03","2010/05/04","2010/05/05",
         "2010/07/19","2010/09/20","2010/09/23","2010/10/11","2010/11/03","2010/11/23",
         "2010/12/23","2011/01/01","2011/01/10","2011/02/11","2011/03/21","2011/04/29",
         "2011/05/03","2011/05/04","2011/05/05","2011/07/18","2011/09/19","2011/09/23",
         "2011/10/10","2011/11/03","2011/11/23","2011/12/23","2012/01/01","2012/01/02",
         "2012/01/09","2012/02/11","2012/03/20","2012/04/29","2012/04/30","2012/05/03",
         "2012/05/04","2012/05/05","2012/07/16","2012/09/17","2012/09/22","2012/10/08",
         "2012/11/03","2012/11/23","2012/12/23","2012/12/24","2013/01/01","2013/01/14",
         "2013/02/11","2013/03/20","2013/04/29","2013/05/03","2013/05/04","2013/05/05",
         "2013/05/06","2013/07/15","2013/09/16","2013/09/23","2013/10/14","2013/11/03",
         "2013/11/04","2013/11/23","2013/12/23","2014/01/01","2014/01/13","2014/02/11",
         "2014/03/21","2014/04/29","2014/05/03","2014/05/04","2014/05/05","2014/05/06",
         "2014/07/21","2014/09/15","2014/09/23","2014/10/13","2014/11/03","2014/11/23",
         "2014/11/24","2014/12/23","2015/01/01","2015/01/12","2015/02/11","2015/03/21",
         "2015/04/29","2015/05/03","2015/05/04","2015/05/05","2015/05/06","2015/07/20",
         "2015/09/21","2015/09/22","2015/09/23","2015/10/12","2015/11/03","2015/11/23",
         "2015/12/23"};

        foreach (string EachStr in StrArr) {
            string[] wkStrArr = EachStr.Split('/');
            DateTime wkDate = new DateTime(
                int.Parse(wkStrArr[0]), int.Parse(wkStrArr[1]), int.Parse(wkStrArr[2]));
            if (wkDate == pDate) return true;
        }
        return false;
    }

    static void DebugPrint(int[,] pCalendarArr)
    {
        for (int Y = 0; Y <= pCalendarArr.GetUpperBound(1); Y++) {
            for (int X = 0; X <= pCalendarArr.GetUpperBound(0); X++) {
                Console.Write("{0,2},", pCalendarArr[X, Y]);
            }
            Console.WriteLine();
        }
    }

    //カレンダーの2次元配列を引数として、最大の長方形の面積を返す
    static int DeriveMaxMenseki(int[,] pCalendarArr)
    {
        int UB_X = pCalendarArr.GetUpperBound(0);
        int UB_Y = pCalendarArr.GetUpperBound(1);

        int MaxMenseki = 0;

        //始点のX座標のループ
        for (int StaX = 0; StaX <= UB_X; StaX++) {
            //始点のY座標のループ
            for (int StaY = 0; StaY <= UB_Y; StaY++) {
                if (pCalendarArr[StaX, StaY] == -1) continue;

                //横幅のループ
                for (int HabaX = 1; StaX + (HabaX - 1) <= UB_X; HabaX++) {
                    //縦幅のループ
                    for (int HabaY = 1; StaY + (HabaY - 1) <= UB_Y; HabaY++) {
                        if (IsTyouhoukei(pCalendarArr, StaX, StaY, HabaX, HabaY) == false) {
                            break;
                        }
                        int Menseki = HabaX * HabaY;
                        if (MaxMenseki < Menseki) MaxMenseki = Menseki;
                    }
                }
            }
        }
        return MaxMenseki;
    }

    //長方形かを判定
    static bool IsTyouhoukei(int[,] pCalendarArr, int pStaX, int pStaY, int pHabaX, int pHabaY)
    {
        for (int X = pStaX; X <= pStaX + pHabaX - 1; X++) {
            for (int Y = pStaY; Y <= pStaY + pHabaY - 1; Y++) {
                if (pCalendarArr[X, Y] == -1) return false;
            }
        }
        return true;
    }
}


実行結果

120ヶ月分の面積の和=1875


解説

DateTimeで日時を管理してます。