AVOID 문제 질문 드립니다.

  • kwangswei
    kwangswei

    으으으으, 3일간 고민하다가 결국에는 또 질문 게시판에 글을 쓰네요 ㅠ.ㅠ

    AVOID 문제입니다.
    오답이 나오는데요. 부분이 잘못 되었는지 검토 부탁 드립니다.

    알고리즘.
    1. 다익스트라 알고리즘을 이용해서 시작점부터 끝점까지의 최단 경로를 구합니다.
    1.1. 이 때 Parent 에 부모 노드를 저장합니다.
    1.2. 최단 경로가 갱신되면 parent 를 비운 뒤 노드를 저장하고,
    1.3. 최단 경로와 같은 cost 의 경로가 발견되어도 parent 에 저장합니다.
    2. 다익스트라 알고리즘이 끝나면 parent 를 통해서 가능한 모든 경로 리스트를 구합니다.
    2.1. 무식하게 재귀로 모든 경로 생성하도록 했습니다.
    3. 모든 경로 리스트에서 각 노드의 빈도를 누적하여 확률을 계산합니다.

    첫번째 예제를 예로 들면,
    다익스트라 알고리즘을 끝내고 나면 parent 에는 다음과 같습니다.
    1 - X
    2 - 1
    3 - 1
    4 - 2, 3

    그럼 위의 parent list 를 가지고 모든 가능한 경로를 생성합니다.
    allpath(4) = allpath(2)+allpath(3) 에 각각 "4" 를 붙인 경로.
    allpath(2) = allpath(1) 에 "2" 를 붙인 경로......

    최종적으로
    1-2-4
    1-3-4
    가 도출 됩니다.

    그럼 빈도를 누적하여 최종적으로 결과를 냅니다.
    1 : 2 = 2/2 = 1/1
    2 : 1 = 1/2
    3 : 1 = 1/2
    4 : 2 = 2/2 = 1/1

    중간에 테스트 코드 삽입하여 모든 경로 제대로 생성하는 지
    확인하였는데 문제가 없어 보입니다...

    0 : 1 3 4
    1 : 1 2 4
    1/2
    1/1
    0 : 1 4 6 8
    1 : 1 3 4 6 8
    2 : 1 2 4 6 8
    3 : 1 4 5 8
    4 : 1 3 4 5 8
    5 : 1 2 4 5 8
    1/3
    1/1
    1/2
    0/1
    0 : 1 3 6 8 9 10
    1 : 1 2 5 7 9 10
    2 : 1 2 4 7 9 10
    2/3
    1/3
    1/3
    1/1

    조언 부탁 드립니다.

    #include <cstdio>
    #include <vector>
    #include <queue>
    
    using namespace std;
    
    const int MAX_V = 100;
    const int INF = 1000000000;
    
    int gcd(int a, int b)
    {
        while( 1 )
        {
            a = a % b;
            if( a == 0 )
                return b;
            b = b % a;
    
            if( b == 0 )
                return a;
        }
    }
    
    void dijkstra(vector<pair<int,int> > * adj,
            vector<int>* parent, 
            int v, 
            int src) {
        vector<int> dist(v, INF);
    
        dist[src] = 0;
        priority_queue<pair<int, int> > pq;
        pq.push(make_pair(0, src));
    
        while ( !pq.empty() ) {
            int cost = -pq.top().first;
            int here = pq.top().second;
            pq.pop();
    
            if ( dist[here] < cost ) continue;
    
            for ( int i =0 ; i < adj[here].size(); ++i){
                int there = adj[here][i].first;
                int nextDist = cost + adj[here][i].second;
    
                if ( dist[there] > nextDist) {
                    parent[there].clear();
                    parent[there].push_back(here);
    
                    dist[there] = nextDist;
                    pq.push(make_pair(-nextDist, there));
                }
                else if ( dist[there] == nextDist ) {
                    parent[there].push_back(here);
                }
            }
        }
    }
    
    
    vector<vector<int> > getAllPath(vector<int> *parent, int v)
    {
        if ( v == 0 )
        {
            vector<vector<int> > allPath;
            vector<int> path;
            path.push_back(0);
            allPath.push_back(path);
            return allPath;
        }
    
        vector<vector<int> > allPath;
        for ( int i = 0; i < parent[v].size(); i++ )
        {
            vector<vector<int> > paths = getAllPath(parent, parent[v][i]);
            for ( int j = 0; j < paths.size(); j++ )
            {
                paths[j].push_back(v);
                allPath.push_back(paths[j]);
            }
        }
    
        return allPath;
    }
    
    int main()
    {
        int C;
        scanf("%d", &C);
    
        while ( C-- ) {
            int N;
            int v, e;
    
            int start, end, cost;
            int point;
    
            vector<pair<int,int> > adj[MAX_V];
            vector<int> parent[MAX_V];
    
            scanf("%d %d %d", &v, &e, &N);
            for ( int i = 0; i < e; i++ ) {
                scanf("%d %d %d", &start, &end, &cost);
                adj[start-1].push_back(make_pair(end-1,cost));
            }
    
            dijkstra( adj, parent, v, 0);
    
            vector<vector<int> > allPath = getAllPath(parent, v-1);
    
            vector<int> p(v,0);
    
            for ( int i = 0; i < allPath.size(); i++ )
            {
                printf("%d : ",i);
                for ( int j = 0; j < allPath[i].size(); j++ )
                {
                    printf("%d ", allPath[i][j]+1);
                    p[allPath[i][j]]++;
                }
                printf("\n");
            }
    
            for ( int i = 0; i < N; i++ )
            {
                int n;
                scanf("%d", &n);
                if ( p[n-1] == 0 )
                    printf("0/1\n");
                else
                {
    
                    int x = gcd(allPath.size(), p[n-1]);
                    printf("%d/%d\n", p[n-1]/x, (int)allPath.size() / x);
                }
            }
        }
    
        return 0;
    }
    

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

    일단 디버그 코드가 남아있네요.

    1
    2 1 2
    2 1 1
    1 2

    이 케이스 테스트해보시면 도움이 될 거 같습니다.


    11년 전 link
  • kwangswei
    kwangswei

    @VOCList 조언 감사합니다. 무방향 그래프에서 한 쪽 방향으로만 제가 넣어줬군요. 해결할 수 있도록 힌트 주셔서 감사합니다~!

    그런데 수정 해도 "시간초과" 가 뜨네요 ㅠ.ㅠ
    다른 방법으로 접근해봐야겠습니다.
    감사합니다.

    덧. 디버그 코드는 일부러 남겨두었습니다~!


    11년 전 link
  • VOCList
    VOCList

    힌트

    아마 모든 경로를 만들어본다는 아이디어가 TLE를 일으키는 원인일 것 같습니다.
    예를 들자면, 시작점이 0 도착점이 101번 노드이며 0 -> 1 ~ 10 노드에 엣지가 하나씩(총 열개), 1 ~ 10 -> 11 ~ 20 에 각각 엣지가 하나씩(총 백개), 11 ~ 20 -> 21 ~ 30 에 각각 하나씩(총 백개), ....
    , 그리고 마지막으로 91 ~ 100 -> 101에 엣지가 하나씩(총 10개) 그려진 그래프를 생각해보면(모든 엣지의 가중치는 1), 최단경로의 갯수는 1 ~ 10에서 하나를 선택, 11 ~ 20에서 하나를 선택 ... 와 같은 방식이 되어 10 ^ 10 개가 나오게 됩니다.

    모든 길을 생성해보는 궁극적인 이유는 각각 노드의 등장 빈도를 세기 위해서이지요. 등장 빈도를 좀 더 효과적으로 세어볼 수 있으면 해결할 수 있지 않을까요.


    11년 전 link
  • kwangswei
    kwangswei

    @VOCList 감사합니다. 아무래도 다익스트라 알고리즘을 다시 찬찬히 따라가보며 노드의 등장 빈도를 셀 수는 없는지 고민해봐야겠습니다. 감사합니다~!!


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