https://www.acmicpc.net/problem/3300

 

3300번: 무어 기계

문제 무어 기계는 상태에 의해서 출력이 결정되는 유한 상태 기계이다. 무어 기계는 이름은 미국의 수학자이자 컴퓨터 과학자 Edward F. Moore의 이름을 따서 지었다. 무어 기계의 상태 전이는 입력�

www.acmicpc.net

Graph 순회 방법을 대충 맞추어서 정리를 합니다.

 

하나는 String을 두어 Push_Back과 erase로 정답을 산출.

그리고 두개의 Stack을 두어 하나는 순회를 하고 다시 되돌아 올 Index를 저장.

다른 하나는 되돌아 왔을 때 어느 Node로 넘어가야 하는지를 알려주는 Stack입니다.

 

지금 개발중인 기능을 마무리 하고 8월 중으로 여러 회사들에 입사지원서를 쓰기 위해 언리얼 개발에 더 전념중입니다.

그러다보니 알고리즘 풀 체력이나 정신력이 부족해 한 문제를 몇 주씩 물고 늘어지게 되는 것 같습니다.

여태까지 못푼 문제들 위주로 잡다보니 어려운 것도 한 몫 하고 있긴 합니다만.

빨리 못푼 문제 다 털어버리고 부족한 부분을 더 다잡고 싶습니다.

'개발일지 > Algorithm' 카테고리의 다른 글

20.07.29 개발일지 - Frogger  (0) 2020.07.29
20.07.28 개발일지 - 무어기계  (0) 2020.07.28
20.07.27 - 무어기계(cont)  (0) 2020.07.27
20.07.26 - 무어 기계(cont)  (0) 2020.07.26
20.07.24 개발일지 - 무어 기계(cont)  (0) 2020.07.24

https://www.acmicpc.net/problem/11100

 

11100번: Frogger

A group of frogs is sitting on an infinite xy grid. The frogs all have non-positive x coordinates. On the grid location (2, 0) there’s a fly. The frogs are hungry and would like to get there to eat the fly. There’s one catch; a frog can only move by ju

www.acmicpc.net

예전에 시도 했는데 풀지 못하고 보류 했던 문제입니다.

 

문제를 정리하자면

1. 개구리는 가로세로로만 움직일 수 있으며, 인접한 다른 개구리를 밟고 그 개구리의 다음 좌표로 이동할 수 있다.

2. 밟힌 개구리는 터져 죽는다.

3. 파리는 {(x, y) | x >= 0, y = 0}에, 개구리는 {(x, y) | x < 0, y = 모든 정수}에 위치한다,

4. 좌표별 파리를 먹을 수 있는 개구리의 최소 숫자를 출력하라. 불가능 할 시 Frogger 출력.

이렇습니다.

 

처음 접했을 때도 4 이후로 규칙을 찾을 수 없어 고민을 하다가 멈췄습니다.

그러다가 심심해서 커뮤니티에 올려봤는데, 누군가가 풀이를 적어줘서 보고 이해를 할 수 있었습니다.

 

https://github.com/marteloge/Programming-contests/blob/master/IDI%20Open/solutions/2007%20solutions.pdf

 

marteloge/Programming-contests

IDI Open, CodeChef, NCPC. Contribute to marteloge/Programming-contests development by creating an account on GitHub.

github.com

요약을 하자면 이렇습니다.

1. 개구리는 가로와 세로로만 움직일 수 있으니 개구리와 파리와의 거리는 맨하튼 거리로 표시한다.

2. 개구리들과 파리와의 가중치의 합을 구한다. Sum(K^d) = D_fly라고 봐도 무방할 것이다.

3. 위 과정을 거치면 개구리와 파리의 평면이 하나의 방정식으로 표시된다.

4. 하지만 5차 이상의 방정식은 근의공식이 존재하지 않는다.

https://m.blog.naver.com/PostView.nhn?blogId=iphone_dev&logNo=80145256483&proxyReferer=https:%2F%2Fwww.google.com%2F

 

N차 방정식의 일반적인 해법(=근의공식)에 대한 고찰

꼴의 방정식(단 a≠0)일반적인 해법 : (단 a≠0) 이미 기원전부터 발견됬던 해법으로 누가 발견했는지도 모...

blog.naver.com

5. 그렇기에 우리는 거리가 0~4일 때의 값만 작성을 하고, 그 위의 값은 frogger를 출력하면 된다.

 

Mathematics 문제는 항상 이런 문제? 매력?이 있습니다.

모르면 절대로 죽었다 깨어나도 풀 수 없지만, 풀면 그 쾌감이 다른 문제보다 더 강렬합니다.

하지만 이 문제는 가중치 계산을 하는 것에 전혀 다가가지 못해서 결국 이렇게 보고 풀 수 밖에 없던 것 같습니다.

 

더보기
#include <iostream>

using namespace std;

int main()
{
    const int Mem[5] = { 1, 2, 4, 8, 20 };
    int times = 0, input = 0;
    cin >> times;
    while (times-- > 0)
    {
        cin >> input;
        if (input < 5)
        {
            cout << Mem[input] << endl;
        }
        else
        {
            cout << "frogger" << endl;
        }
    }
    return 0;
}

https://www.acmicpc.net/problem/3300

 

3300번: 무어 기계

문제 무어 기계는 상태에 의해서 출력이 결정되는 유한 상태 기계이다. 무어 기계는 이름은 미국의 수학자이자 컴퓨터 과학자 Edward F. Moore의 이름을 따서 지었다. 무어 기계의 상태 전이는 입력�

www.acmicpc.net

무어 머신을 입력받고 이를 그래프로 표현하는 부분을 구상하였습니다.

원래는 이대로 끝내려 했지만 4일에 한번 있는 저녁 운동 없는 날이기도 하고,
요즘 알고리즘을 열심히 안한 느낌도 있어서 구현까지 해보았습니다.

테스트 결과 왠만한 경우에서 잘 작동하고 있습니다.

 

더보기
#include <iostream>
#include <sstream>
#include <string>   
#include <stack>
#include <vector>
#include <algorithm>

using namespace std;

int FindFormerNode(const vector<int>& Heights, const int& height, const int& index)
{
    for (int i = index - 1; i >= 0; --i)
    {
        if (Heights[i] < height)
        {
            return i;
        }
    }
    return 0;
}

vector<int> FindFormerNodes(const vector<vector<int>>& Nodes, const vector<int>& Heights, const int& height, const int& index, const int& gap)
{
    vector<int> ret;
    for (int i = index - 1; i >= 0; --i)
    {
        if (height == Heights[i])
        {
            break;;
        }
        if (!Nodes[i].empty())
        {
            continue;
        }
        if (height - Heights[i] >= gap)
        {
            ret.push_back(i);
        }
    }
    return ret;
}

int main()
{
    int testtime = 0;
    
    cin >> testtime;

    while (testtime-- > 0)
    {
        string machine, testcase;

        char result = '!', special = 0;
        int gap = 0, height = 0, index = 0;

        vector<char> Spells;
        vector<int> Indices, Heights;
        vector<vector<int>> Nodes;

        cin >> machine >> testcase;

        for (const auto& iter : machine)
        {
            if (iter == '(')
            {
                ++height;
                ++gap;
                special = iter;
                continue;
            }
            if (iter == ')')
            {
                --height;
                --gap;
                special = iter;
                continue;
            }
            if (iter == '|')
            {
                special = iter;
                continue;
            }
            switch (special)
            {
            case '|':
            {
                Spells.push_back(iter);
                Heights.push_back(height);
                Nodes.push_back(vector<int>());
                Nodes[FindFormerNode(Heights, height, index)].push_back(index);
                Indices.push_back(index++);
            }
                break;
            case ')':
            {
                Spells.push_back(iter);
                Heights.push_back(height);
                Nodes.push_back(vector<int>());
                auto Former = FindFormerNodes(Nodes, Heights, height, index, gap);
                for (const auto& i : Former)
                {
                    Nodes[i].push_back(index);
                }
                Indices.push_back(index++);
                gap = 0;
            }
                break;
            default:
            {
                Spells.push_back(iter);
                Heights.push_back(height);
                Nodes.push_back(vector<int>());
                if (Nodes.size() > 1)
                {
                    Nodes[index - 1].push_back(index);
                }
                Indices.push_back(index++);
                gap = 0;
            }
                break;
            }
            special = iter;
        }
        cout << endl;

        
        cout << result << endl;
    }
    return 0;
}

 

우선 Special Character 처리입니다.

흐름에 영향을 주는 Character는 (, |, ) 3가지가 있습니다.

 

( 문자는 입력 시 현재 높이와 이전 Node로부터의 높이가 1씩 올라갑니다.

 

) 문자는 반대로 입력 시 현재 높이와 이전 Node로부터의 높이가 1씩 내려갑니다.

 

| 문자는 입력 자체로는 영향이 없습니다.

 

이 특수 문자는 자체가 입력될 때는 아무 행동도 하지 않습니다.

그렇기에 Special이라는 메모리에 따로 저장을 합니다.

 

그리고 위 3 문자가 아닌 다른 문자 입력 시 Special 문자에 따라 흐름이 달라지게 됩니다.

 

( 문자 입력 시에는 앞 Node에 자신의 Index를 추가합니다.

하지만 이는 일반 문자도 동일하기에 따로 처리하지 않고 있습니다.

 

| 문자는 입력 시 자신의 선행 Node를 찾아 그 Node에 Index를 추가합니다.

선행 Node는 자신의 앞에 있는 Index 중 자신의 높이보다 낮은 높이를 지닌 첫번째 Node입니다.

 

) 문자는 입력 시 자신의 선행 Node을 찾아 그 Node에 Index를 추가합니다.

이 때 선행 Node는 | 문자와 다르게 검색합니다.

 

| 문자는 선행 Node가 자기 자신과 연속적으로 붙어 있기에 단순 비교로 가능합니다.

하지만 )문자는 모든 Node를 검색해야 하기에 단순 비교로는 다른 군(| 문자 앞의 문자들)을 구분할 수 없게 됩니다.

이 때문에 이전 Node와의 거리인 gap이 추가된 것입니다.

 

먼저 비교 Node와 자신의 높이가 동일하다면 함수를 마칩니다.

이는 이미 ) 범위 안의 연산이 끝났다는 것을 의미하기 때문입니다.

 

또한 비교 Node가 이미 다른 Index 값을 가지고 있으면 다음 연산으로 넘어갑니다.

) 연산은 연속적인 Node의 리스트 중 꼬리에만 붙습니다.

Node가 이미 다른 Index 값을 가지고 있다면 이는 꼬리가 아니라는 의미입니다.

 

위 두가지 경우를 제외하고, 두 Node의 높이 차가 gap보다 크거나 같을 경우 Return 할 Vector에 값을 추가합니다.

 

여기서 중요한 조건은 두번째입니다.

그 이유는 세번째 조건은 같은 군에서 이미 Node 값이 있는 것들도 옳다고 판단하기 때문입니다.

그리고 그 조건을 먼저 제거해주는 것이 두번째 조건입니다.

 

세번째 조건은 금새 다다를 수 있지만, 두번째 조건이 없다면 한참을 해맬 것입니다.

 

여기까지 짜놓고 끝까지 작성하지 않은 이유는
아직 이 Graph를 효율적으로 순회해서 탐색하는 방법은 명확하게 정하지 못했기 때문입니다.

일단 시도해보는 방법도 있지만,
이 문제를 풀어오면서 생각을 오래해서 정리를 하는 것이 좋은 답을 도출한다는 것을 느꼈습니다.

이 느낌을 더 느껴보고 싶습니다.

 

그래서 내일 Graph 순회 방법을 고려해보고자 합니다.

일단 가지고 있는 아이디어는 Spells 길이와 동일한 Vector<int>iterator를 두는 것입니다.

Graph를 한 방향으로만 가는 것이 아니라 다른 방향으로도 순회해야 하는데,

재귀문은 메모리 문제가 발생할 것 같기에 이런 방법을 사용해야 할 것 같습니다.

 

더보기
        cout << "Indices:\t";
        for (const auto& i : Indices)
        {
            cout << i << " ";
        }
        cout << endl;
        cout << "Spells:\t\t";
        for (const auto& i : Spells)
        {
            cout << i << " ";
        }
        cout << endl;
        cout << "Heights:\t";
        for (const auto& i : Heights)
        {
            cout << i << " ";
        }
        cout << endl;
        for (const auto& i : Nodes)
        {
            for (const auto& j : i)
            {
                cout << j << " ";
            }
            cout << endl;
        }

 

https://www.acmicpc.net/problem/3300

 

3300번: 무어 기계

문제 무어 기계는 상태에 의해서 출력이 결정되는 유한 상태 기계이다. 무어 기계는 이름은 미국의 수학자이자 컴퓨터 과학자 Edward F. Moore의 이름을 따서 지었다. 무어 기계의 상태 전이는 입력�

www.acmicpc.net

대략적인 가닥은 잡혔는데 핵심적인 부분의 방식을 아직 구상하지 못하고 있습니다.

우선 대략적인 부분.

입력된 무어 머신을 앞에서부터 순회합니다.

그리고 Spells Vector와 Index Vector로 나누어서 관리합니다.

Spells는 무어머신에 입력된 Alphabat. 즉 State의 저장입니다.

중복된 알파뱃이 입력될 수 있으므로 이를 따로 관리하기 위해 Vector로 관리를 합니다.

 

그리고 이 State들간의 관계. 즉 Condition을 최대한 가볍게 구현하기 위해 Vector<Vector<int>>를 추가했습니다.

이 Vector는 Index값으로 State들간의 관계를 나타냅니다.

선행 State와 후행 State가 일대다 관계도, 다대일 관계도 가능하기에
어쩔 수 없이 이차원 Vector를 사용해야 할 것 같습니다.

 

무어 머신을 순회하면서 Alphabat이 들어오면 기본적으로 선행 Alphabat의 Index Vector에 값이 추가됩니다.

단, Alphabat이 아닌 특수 문자가 들어올 때에는 특수한 작업이 발생합니다.

이 때 문제가 발생합니다.

 

) 문자가 들어온 이후의 첫 Alphabat은 선행 State들과 연결을 지어야 합니다.

이것이 가능하려면 선행 Alphabat이 어디부터 어디까지인지 판단을 할 수 있어야 합니다.

그런데 이를 판단하는 방식을 아직 구상하지 못했습니다.

 

우선은 height Vector를 먼저 도입해볼까 합니다.

현재 Alphabat과 인접한 Alphabat과 같은 Height를 지닌 연속적인 모든 Alphabat을

선행 Alphabat으로 판정하는 것입니다.

 

그 이후에 형성된 그래프를 순회하는 것도 고민을 해봐야 할 것 같습니다.

https://www.acmicpc.net/problem/3300

 

3300번: 무어 기계

문제 무어 기계는 상태에 의해서 출력이 결정되는 유한 상태 기계이다. 무어 기계는 이름은 미국의 수학자이자 컴퓨터 과학자 Edward F. Moore의 이름을 따서 지었다. 무어 기계의 상태 전이는 입력�

www.acmicpc.net

이전에 짰던 코드가 입력되는 String에 반복적인 알파뱃이 존재 할 때
Shift 과정에서 오류가 발생한다는 점을 깨달았습니다.

더 큰 문제는 추가적인 복잡한 구조나 대량의 메모리가 없이는 개선을 할 수 없다는 점이었습니다.

 

그래서 구조를 다시 짜보고 있습니다.

처음에는 struct를 이용한 Graph를 이용해보려 했습니다.

runtime 상에서 메모리를 잡는 거은 큰 부하가 걸리므로 Stack Object들로 관리를 하였습니다.

하지만 Graph라고 해도 Directed Graph라서 흐름을 역행하는 케이스를 검색하는 것에 문제가 발생하였습니다.

 

현재는 여기까지 개발을 한 상태입니다.

그리고 일지를 적다가 Graph를 Array로 표현하는 방법을 떠올렸습니다.

입력된 Machine에서 모든 State를 Vector에 순차적을로 담고,
각 State가 어떤 State로 갈 수 있는지 index 값을 Vector로 담고 있는 방식입니다.

 

여기서 문제가 될 수 있는 부분은 두가지입니다.

하나는 하향식이든 상향식이든 일대 다 관계가 발생할 수 있다는 점.

다른 하나는 State가 많아질수록 기하급수적으로 Graph 정보가 많아진다는 점입니다.

 

우선은 이 구현하던 것을 지우고 Array 식으로 변경해서 새로 구현을 해보려 합니다.

아무래도 Vector보다는 부하가 적을 것 같아서입니다.

https://www.acmicpc.net/problem/3300

 

3300번: 무어 기계

문제 무어 기계는 상태에 의해서 출력이 결정되는 유한 상태 기계이다. 무어 기계는 이름은 미국의 수학자이자 컴퓨터 과학자 Edward F. Moore의 이름을 따서 지었다. 무어 기계의 상태 전이는 입력�

www.acmicpc.net

예시는 다 통과가 될 정도로 수정을 하고 제출을 해보았는데 런타임 에러가 발생했습니다.

몇가지 예시를 종이에 더 적어보았는데 이걸 확대해서 테스트 해봐야겠습니다.

썩 마음에 드는 코드 방식도 아닌데 이게 문제가 생기니까 막막합니다.

이거 언제 또 고치지...

https://www.acmicpc.net/problem/3300

 

3300번: 무어 기계

문제 무어 기계는 상태에 의해서 출력이 결정되는 유한 상태 기계이다. 무어 기계는 이름은 미국의 수학자이자 컴퓨터 과학자 Edward F. Moore의 이름을 따서 지었다. 무어 기계의 상태 전이는 입력�

www.acmicpc.net

버그가 나는 부분은 수정을 하였습니다.

탐색이 모두 끝날 때 되돌아 갈 위치가 없는데 받아오려 해서 문제가 생겼습니다.

 

몇가지 테스트를 하였는데 예시랑 맞지 않는 답이 출력되어 내일 자세히 디버깅을 해보려고 합니다.

https://redchiken.tistory.com/209

 

20.07.20 개발일지 - 무어 기계(cont)

https://www.acmicpc.net/problem/3300 3300번: 무어 기계 문제 무어 기계는 상태에 의해서 출력이 결정되는 유한 상태 기계이다. 무어 기계는 이름은 미국의 수학자이자 컴퓨터 과학자 Edward F. Moore의 이름을

redchiken.tistory.com

면접을 갔다 오느라 많이 시간을 투자하지 못했습니다.

입력값을 처리하는 부분을 구현하였는데, 몇가지 index 오류가 발생하고 있습니다.

이 부분을 수정하면 생각한 방식이 옳은지, 시간 안에 동작 하는지 알 수 있을 것 같습니다.

https://www.acmicpc.net/problem/3300

 

3300번: 무어 기계

문제 무어 기계는 상태에 의해서 출력이 결정되는 유한 상태 기계이다. 무어 기계는 이름은 미국의 수학자이자 컴퓨터 과학자 Edward F. Moore의 이름을 따서 지었다. 무어 기계의 상태 전이는 입력�

www.acmicpc.net

어제도 상당히 복잡해서 하다가 말았는데 오늘도 역시 복잡했습니다.

꽤 시간을 투자 한 끝에서야 대략적인 구조를 완성 할 수 있었습니다.

 

일단 가정은 다음과 같습니다.

1. 비어있는 심볼에 공백 문자는 들어올 수 없다.

2. 비어있는 심볼 없이 일치하는 문장이 완성된다면 비어있는 심볼을 유일하게 유추할 수 없다.

 

사실 중요한건 2번입니다.

만약 2번이 성립하지 않으면 지금보다 더 복잡할 것입니다.

 

제가 생각하는 방식은 대략 다음과 같습니다.

1. 괄호가 열리면 높이를 1 증가시킨다.

2. 괄호가 닫히면 높이를 1 감소시킨다. 변화된 높이가 저장된 높이보다 1 작을 경우 입력 트리거를 킨다.

3. 알파벳('_' 포함)이 입력된 경우, 입력 트리거가 켜져 있으면 입력된 값을 Stack에 담는다.

4. '|'이 입력 되면 index를 저장하고 입력 트리거를 끈다.

5. 마지막 문자까지 연산이 마친 뒤 값을 비교한다.

문장에 '_'이 포함되어 있지 않고 예시 문자와 동일하다면 결과에 '_'를 저장하고 탈출한다.

문장에 '_'이 포함되어 있고 나머지 문자들이 예시 문자와 동일하다면 결과에 '_'에 대응하는 문자를 저장한다.

이 외에는 저장된 '|' index로 iterator를 이동시킨다.

 

현재 4번까지는 정리 되었고 5번만 구현해서 테스트를 하면 됩니다.

이렇게 구상한 이유와 기타 주의사항 등은 정답을 맞춘 뒤 작성하겠습니다.

https://www.acmicpc.net/problem/3300

 

3300번: 무어 기계

문제 무어 기계는 상태에 의해서 출력이 결정되는 유한 상태 기계이다. 무어 기계는 이름은 미국의 수학자이자 컴퓨터 과학자 Edward F. Moore의 이름을 따서 지었다. 무어 기계의 상태 전이는 입력�

www.acmicpc.net

원래 Frogger를 풀려고 했는데 문제 해석까지만 되고 규칙을 찾지 못하여 다른 문제를 선택했습니다.

 

입력되는 직병렬 무어 기계와 입력값을 보고 지워진 심볼을 유추하는 문제입니다.

유추가 된다면 유추값을, 안 된다면 _를, 잘못된 입력 값이라면 !를 출력하면 됩니다.

 

처음에는 모든 경우에 대한 그래프를 만들어서 그래프 순회를 할까 싶었지만,
그래프 만드는 것 자체가 시간이 많이 드는 작업이라 시간 초과가 될 것 같았습니다.

그래서 Array로 Tree를 만들듯이 단순 순회로 입력을 조정해보려 합니다.

 

이에 대한 제대로 된 로직은 차후 짜보겠습니다.

어제서부터 피로가 쌓였는지 낮에도 비몽사몽해서 일찍 정리하고 하루종일 쉬려 합니다.

+ Recent posts