AOJ本の読書メモ   AOJ    次のAOJの問題へ    前のAOJの問題へ

AOJ 0531 ペンキの色


問題へのリンク


C#のソース

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static string InputPattern = "InputX";

    static List<string> GetInputList()
    {
        var WillReturn = new List<string>();

        if (InputPattern == "Input1") {
            WillReturn.Add("15 6");
            WillReturn.Add("10");
            WillReturn.Add("1 4 5 6");
            WillReturn.Add("2 1 4 5");
            WillReturn.Add("1 0 5 1");
            WillReturn.Add("6 1 7 5");
            WillReturn.Add("7 5 9 6");
            WillReturn.Add("7 0 9 2");
            WillReturn.Add("9 1 10 5");
            WillReturn.Add("11 0 14 1");
            WillReturn.Add("12 1 13 5");
            WillReturn.Add("11 5 14 6");
            WillReturn.Add("0 0");
            //5
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static long[] GetSplitArr(string pStr)
    {
        return (pStr == "" ? new string[0] : pStr.Split(' ')).Select(pX => long.Parse(pX)).ToArray();
    }

    static long mH;
    static long mW;

    struct RectInfoDef
    {
        internal long StaX;
        internal long StaY;
        internal long EndX;
        internal long EndY;
    }
    static List<RectInfoDef> mRectInfoList = new List<RectInfoDef>();

    static long UB_X;
    static long UB_Y;
    static long[,] mImosArr;

    static void Main()
    {
        List<string> InputList = GetInputList();

        long[] wkArr = { };
        Action<string> SplitAct = (pStr) => wkArr = GetSplitArr(pStr);

        int CurrInd = 0;
        while (true) {
            SplitAct(InputList[CurrInd]);
            mW = wkArr[0];
            mH = wkArr[1];
            if (mW == 0 && mH == 0) {
                break;
            }

            long N = long.Parse(InputList[CurrInd + 1]);
            mRectInfoList.Clear();
            for (int I = CurrInd + 2; I <= CurrInd + 2 + N - 1; I++) {
                SplitAct(InputList[I]);
                RectInfoDef WillAdd;
                WillAdd.StaX = wkArr[0];
                WillAdd.StaY = wkArr[1];
                WillAdd.EndX = wkArr[2] - 1;
                WillAdd.EndY = wkArr[3] - 1;
                mRectInfoList.Add(WillAdd);
            }
            Solve();
            CurrInd += 2 + (int)N;
        }
    }

    static void Solve()
    {
        // X座標のset
        var XSet = new HashSet<long>() { 0, mW - 1 };

        // Y座標のset
        var YSet = new HashSet<long>() { 0, mH - 1 };

        foreach (RectInfoDef EachRectInfo in mRectInfoList) {
            XSet.Add(EachRectInfo.StaX - 1);
            XSet.Add(EachRectInfo.StaX);
            XSet.Add(EachRectInfo.EndX);
            XSet.Add(EachRectInfo.EndX + 1);

            YSet.Add(EachRectInfo.StaY - 1);
            YSet.Add(EachRectInfo.StaY);
            YSet.Add(EachRectInfo.EndY);
            YSet.Add(EachRectInfo.EndY + 1);
        }
        XSet.RemoveWhere(pX => pX < 0 || mW - 1 < pX);
        YSet.RemoveWhere(pX => pX < 0 || mH - 1 < pX);

        Dictionary<long, long> ZaatuDictX = DeriveZaatuDict(XSet);
        Dictionary<long, long> ZaatuDictY = DeriveZaatuDict(YSet);

        UB_X = ZaatuDictX.Values.Max();
        UB_Y = ZaatuDictY.Values.Max();
        mImosArr = new long[UB_X + 1, UB_Y + 1];

        // 二次元いもす法
        foreach (RectInfoDef EachRectInfo in mRectInfoList) {
            long NewStaX = ZaatuDictX[EachRectInfo.StaX];
            long NewStaY = ZaatuDictY[EachRectInfo.StaY];
            long NewEndX = ZaatuDictX[EachRectInfo.EndX] + 1;
            long NewEndY = ZaatuDictY[EachRectInfo.EndY] + 1;

            mImosArr[NewStaX, NewStaY]++;
            if (NewEndX <= UB_X) {
                mImosArr[NewEndX, NewStaY]--;
            }
            if (NewEndY <= UB_Y) {
                mImosArr[NewStaX, NewEndY]--;
            }
            if (NewEndX <= UB_X && NewEndY <= UB_Y) {
                mImosArr[NewEndX, NewEndY]++;
            }
        }

        // 横方向の累積和を求める
        for (int X = 1; X <= UB_X; X++) {
            for (int Y = 0; Y <= UB_Y; Y++) {
                mImosArr[X, Y] += mImosArr[X - 1, Y];
            }
        }

        // 縦方向の累積和を求める
        for (int Y = 1; Y <= UB_Y; Y++) {
            for (int X = 0; X <= UB_X; X++) {
                mImosArr[X, Y] += mImosArr[X, Y - 1];
            }
        }

        long Result = ExecBFS();
        Console.WriteLine(Result);
    }

    // BFSを行い、何個の0の島があるかを判定
    static long ExecBFS()
    {
        mVisitedSet.Clear();

        long ShimaCnt = 0;
        for (int X = 0; X <= UB_X; X++) {
            for (int Y = 0; Y <= UB_Y; Y++) {
                if (mImosArr[X, Y] != 0) continue;

                long CurrHash = GetHash(X, Y);
                if (mVisitedSet.Contains(CurrHash)) {
                    continue;
                }
                ExecBFSHelper(X, Y);
                ShimaCnt++;
            }
        }
        return ShimaCnt;
    }

    static void ExecBFSHelper(long pStaX, long pStaY)
    {
        var Que = new Queue<JyoutaiDef>();
        JyoutaiDef WillEnqueue;
        WillEnqueue.CurrX = pStaX;
        WillEnqueue.CurrY = pStaY;
        Que.Enqueue(WillEnqueue);

        while (Que.Count > 0) {
            JyoutaiDef Dequeued = Que.Dequeue();

            Action<long, long> EnqueueAct = (pNewX, pNewY) =>
            {
                if (pNewX < 0 || UB_X < pNewX) return;
                if (pNewY < 0 || UB_Y < pNewY) return;

                if (mImosArr[pNewX, pNewY] != 0) return;

                long CurrHash = GetHash(pNewX, pNewY);
                if (mVisitedSet.Add(CurrHash)) {
                    WillEnqueue.CurrX = pNewX;
                    WillEnqueue.CurrY = pNewY;
                    Que.Enqueue(WillEnqueue);
                }
            };

            EnqueueAct(Dequeued.CurrX, Dequeued.CurrY - 1);
            EnqueueAct(Dequeued.CurrX, Dequeued.CurrY + 1);
            EnqueueAct(Dequeued.CurrX - 1, Dequeued.CurrY);
            EnqueueAct(Dequeued.CurrX + 1, Dequeued.CurrY);
        }
    }

    static HashSet<long> mVisitedSet = new HashSet<long>();

    struct JyoutaiDef
    {
        internal long CurrX;
        internal long CurrY;
    }

    static long GetHash(long pX, long pY)
    {
        return pX * 10000 + pY;
    }

    //////////////////////////////////////////////////////////////////////////
    // 列挙を引数として、座標圧縮し、座圧後の値[座圧前の値]なDictを返す
    //////////////////////////////////////////////////////////////////////////
    static Dictionary<long, long> DeriveZaatuDict(IEnumerable<long> pEnum)
    {
        var ZaatuDict = new Dictionary<long, long>();
        var ValSet = new HashSet<long>(pEnum);
        long No = 0;
        foreach (long EachVal in ValSet.OrderBy(pX => pX)) {
            ZaatuDict[EachVal] = No;
            No++;
        }
        return ZaatuDict;
    }
}


解説

座圧した二次元グリッドで、いもす法で集計してから
BFSしてます。