DICTIONARY 문제 검토 부탁 드립니다.

  • kwangswei
    kwangswei

    안녕하세요.

    DICTIONARY 검토 요청 드립니다.

    알고리즘은 아래와 같습니다.

    gg
    kia
    lotte
    lg
    hanhwa
    를 예로 들어 설명하겠습니다.

    1. 입력 문자열로부터 문자 간의 순서 그래프를 만듭니다.
      g->k
      k->l
      o->g
      l->h

    2. 위상 정렬을 하기 위하여 dfs 를 수행합니다.
      2-1. 첫번째 dfs 수행 결과를 결과 리스트인 orders 에 추가합니다. 알파벳 순서이기 때문에 g-k-l-h 가 반환됩니다.
      2-1. 두번째 dfs 를 수행하면 o 가 반환 됩니다. 이 것을 orders 의 '앞' 에 붙입니다.

    3. 최종적으로 나온 o-g-k-l-h 리스트를 순회하며 반대 경로가 있는지 확인하여 cycle 이 있는지 검토 합니다. 아래 순서로 체크할 것 입니다.
      g->o
      k->o
      k->g
      l->o
      l->g
      l->k
      h->o
      h->g
      h->k
      h->l

    4. 위상 정렬 상에 없는 알파벳들을 orders 뒤에 순차적으로 붙입니다.
      o-g-k-l-h-a-b-c-d-.......-w-x-y-z

    5. 결과 출력.

    알고리즘 결과는 아래와 같이 나옵니다.
    INVALID HYPOTHESIS
    ogklhabcdefijmnpqrstuvwxyz
    deiotabcfghjklmnpqrsuvwxyz

    순서 관계가 있으면 먼저 출력이 되므로 세번째 예제 같은 경우 책과는 다르게 deiotabcd.....로 출력이 됩니다.
    문제에는 가능한 순서가 여러 개일 경우 아무거나 출력해도 된다고 해서 마지막 문제 답을 그냥 놔두었는데 혹시 문제가 되는지요??

    검토 부탁 드립니다.

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <list>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    #define ALPHABET_CNT 26
    
    bool visited[ALPHABET_CNT];
    vector<int> adj[ALPHABET_CNT];
    
    void dfs(int idx, list<int>& path)
    {
        visited[idx] = true;
        path.push_back(idx);
        for ( int i = 0; i < adj[idx].size(); ++i )
        {
            int there = adj[idx][i];
            if ( !visited[there] )
                dfs(there, path);
        }
    }
    
    list<int> getAlphabetOrder()
    {
        list<int> orders;
    
        for ( int i = 0; i < ALPHABET_CNT; i++ )
        {
            if ( !visited[i] && !adj[i].empty() )
            {
                list<int> order;
                dfs(i, order);
                orders.splice(orders.begin(), order);
            }
        }
    
        for ( list<int>::iterator itor = orders.begin(); itor != orders.end(); ++itor )
            for ( list<int>::iterator itor2 = orders.begin(); itor2 != itor; ++itor2 )
                if ( find( adj[*itor].begin(), adj[*itor].end(), *itor2) != adj[*itor].end() )
                    return list<int>();
    
        for ( int i = 0; i < ALPHABET_CNT; i++ )
            if ( !visited[i] )
                orders.push_back(i);
    
        return orders;
    }
    
    // a < b
    void getGraph(string a, string b)
    {
        string::iterator itA = a.begin();
        string::iterator itB = b.begin();
    
        while ( itA != a.end() && itB != b.end() )
        {
            if ( *itA != *itB )
            {
                adj[*itA-'a'].push_back(*itB-'a');
                break;
            }
            itA++;
            itB++;
        }
    }
    
    int main()
    {
        int T;
        cin >> T;
        while ( T-- )
        {
            for ( int i = 0; i < ALPHABET_CNT; i++ )
            {
                visited[i] = false;
                adj[i].clear();
            }
    
            int N;
            cin >> N;
    
            string first;
            cin >> first;
            for ( int i = 0; i < N-1; i++ )
            {
                string next;
                cin >> next;
                getGraph(first, next);
                first = next;
            }
            list<int> result = getAlphabetOrder();
    
            if ( result.empty() )
                cout << "INVALID HYPOTHESIS" << endl;
            else
            {
                for ( list<int>::iterator itor = result.begin(); itor != result.end(); ++itor)
                    printf("%c", *itor + 'a');
                cout << endl;
            }
        }
    
        return 0;
    }
    

    11년 전
2개의 댓글이 있습니다.
  • VOCList
    VOCList

    1
    4
    aa
    ac
    b
    c

    케이스에 잘 구동되지 않을 것 같네요. 이유는...

    위상정렬 구현이 잘못되어있어요. 한 번 확인해봐주세요~


    11년 전 link
  • kwangswei
    kwangswei

    VOCList // 감사합니다. 책의 그림을 대충 눈으로 따라가기만 했더니 제가 잘못 이해하고 있었군요!! 다시 차근차근 그려보고 고치니 해결 되었습니다. 감사합니다.


    11년 전 link
  • 정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면 온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야 합니다. 현재 문제를 푸셨습니다.