매일매일 코테풀기 (일시 중단!)

(2024-11-05) 4 문제 : 백준 - 3108 (로고)

오의현 2024. 11. 5. 21:39

 

겹치는 사각형들끼리 그룹을 만들어서 몇개의 그룹이 나오는지 구하는 문제이다.

(겹쳐있는 사각형들끼리는 한 번에 그릴 수 있으므로)

 

먼저, 사각형이 겹쳐있는지 판별해준다. AABB 충돌검사로 간단하게 해결할 수 있다. 하지만, 한 가지 예외가 있는데, 한 사각형이 다른 사각형의 내부에 완전히 포함되는 경우이다. 이 경우엔 펜을 올렸다가 다시 내려야 하기 때문에 이 경우는 제외해준다. 

 

DFS를 통해 충돌하는 사각형을 모두 그룹화해주면 된다. 그 이후 그룹의 개수를 출력하면 되는데 역시나 한가지 예외가 또 존재한다. 바로 시작점에서 바로 그림을 그릴 수 있는 경우이다. (시작할 땐 펜을 내린 상태로 시작하므로 PU없이 그림을 그릴 수 있다.)

 

그러므로 시작점에서 바로 그림을 그릴 수 있는 경우엔 그룹의 개수에서 1을 뺀 값을 출력해야 한다.

 

본인은 Left가 0이거나 Right가 0인 상황에서 사각형의 y2는 양수, 사각형의 y1은 음수인 경우 혹은 Top이나 Down이 0인 상황에서 Left가 음수거나 Right가 양수인 상황에 시작점에서 바로 그릴 수 있다고 판단하였다.

 

#include <iostream>
#include <vector>
#include <algorithm>

void Init()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
}

struct Rect
{
    int Left = 0;
    int Top = 0;
    
    int Right = 0;
    int Down = 0;
};

bool AABB(const Rect& _First, const Rect& _Second)
{
    return !(_First.Right < _Second.Left || _First.Left > _Second.Right || _First.Top > _Second.Down || _First.Down < _Second.Top);
}

bool IsInnerRect(const Rect& _First, const Rect& _Second)
{
    if (_First.Left < _Second.Left && _First.Right > _Second.Right && _First.Top < _Second.Top && _First.Down > _Second.Down)
    {
        return true;
    }

    if (_Second.Left < _First.Left && _Second.Right > _First.Right && _Second.Top < _First.Top && _Second.Down > _First.Down)
    {
        return true;
    }

    return false;
}

void DFS(const std::vector<Rect>& _Rects, std::vector<int>& _IsCheck, int _Index, int _Count)
{
    _IsCheck[_Index] = _Count;

    for (int i = 0; i < _Rects.size(); i++)
    {
        if (i == _Index)
        {
            continue;
        }

        if (_IsCheck[i] != -1)
        {
            continue;
        }

        if (AABB(_Rects[i], _Rects[_Index]) == true && IsInnerRect(_Rects[i], _Rects[_Index]) == false)
        {
            DFS(_Rects, _IsCheck, i, _Count);
        }
    }
}

int main()
{
    Init();

    int NumRect = 0;
    std::cin >> NumRect;

    std::vector<Rect> Rects(NumRect);
    for (int i = 0; i < NumRect; i++)
    {
    	std::cin >> Rects[i].Left >> Rects[i].Top >> Rects[i].Right >> Rects[i].Down;
    }

    int CollisionCount = 0;
    std::vector<int> CollisionOrder(NumRect, -1);

    while (true)
    {
        auto FindIter = std::find(CollisionOrder.begin(), CollisionOrder.end(), -1);

        if (FindIter == CollisionOrder.end())
        {
            break;
        }

        int Index = FindIter - CollisionOrder.begin();

        DFS(Rects, CollisionOrder, Index, CollisionCount);
        CollisionCount++;
    }

    int Answer = CollisionCount;
    
    for (int i = 0; i < NumRect; i++)
    {
        if((Rects[i].Left == 0 || Rects[i].Right == 0) && (Rects[i].Top <= 0 && Rects[i].Down >= 0))
        {
            Answer--;
            break;
        }
        
        if ((Rects[i].Top == 0 || Rects[i].Down == 0) && (Rects[i].Left <= 0 && Rects[i].Right >= 0))
        {
            Answer--;
            break;
        }
    }

    std::cout << Answer;

    return 0;
}