UKEIRETRIP 문제 시간초과 질문

  • veckal
    veckal

    문제 링크

    풀다가 계속 시간초과가 나서 질문 드립니다.
    해답 보고 거의 그대로 구현한 거 같은데 안되네요 ㅠㅠ
    dijkstra 쓰는데 n^2, 확률 뿌리는데 n^2logn쯤 드는거 같습니다
    어디서 시간을 더 줄일 수 있는지 코드 봐주시면 감사하겠습니다.

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<map>
    #include<algorithm>
    using namespace std;
    
    typedef struct navi {
        int u, d;
    } point;
    
    const int INF = 987654321;
    int t, n, m, q, vi, ui, di, b;
    int distant[10000], prevnode[10000], shortest[10000];
    double probability[10000], remainprob[10000], superpass[10000];
    bool isinS[10000];
    map<pair<int, int>, int> edge;
    
    bool compareObj(const point& a, const point& c) {
        return (a.d < c.d) || (a.d == c.d && a.u < c.u);
    }
    
    int main() {
        //freopen("input.txt", "r", stdin);
        scanf("%d", &t);
        while(t--) {
            // input
            scanf("%d%d", &n, &m);
            edge.clear();
            for (int i=0; i<m; i++) {
                scanf("%d%d%d", &vi, &ui, &di);
                edge[pair<int, int>(ui-1, vi-1)] = edge[pair<int, int>(vi-1, ui-1)] = di;
            }
    
            // dijkstra's algorithm
            for (int i=0; i<n; i++)
                distant[i] = INF;
            memset(isinS, 0, sizeof(isinS));
            memset(prevnode, -1, sizeof(prevnode));
            distant[n-1] = 0;
            for(int j=0; j<n; j++) {
                int u = -1, d = INF;
                for (int i=0; i<n; i++) {
                    if (!isinS[i] && (distant[i] < d)) {
                        u = i; d = distant[i];
                    }
                }
                if (!~u) break;
                shortest[j] = u;
                isinS[u] = true;
                for (int i=0; i<n; i++) {
                    map<pair<int, int>, int>::iterator it = edge.find(pair<int, int>(u, i));
                    if (it != edge.end() && (distant[i] > distant[u] + it->second || (distant[i] == distant[u] + it->second && prevnode[i] > u))) {
                        distant[i] = distant[u] + it->second;
                        prevnode[i] = u;
                    }
                }
            }
    
            // spread probability
            bool start = false;
            probability[0] = 1;
            for (int i=1; i<n; i++)
                probability[i] = 0;
            for (int i=n-1; i>=0; i--) {
                if (shortest[i] == 0)
                    start = true;
                if (!start)
                    continue;
                int u = shortest[i];
                double comsat = 1;
                point city[10001];
                int citynum = 0;
                for (int j=0; j<n; j++) {
                    map<pair<int, int>, int>::iterator it = edge.find(pair<int, int>(u, j));
                    if (it != edge.end() && (distant[j] < distant[u])) {
                        city[citynum].u = j; city[citynum].d = it->second; citynum++;
                    }
                }
                sort(city, city+citynum, compareObj);
                for (int j=0; j<citynum; j++) {
                    comsat /= 2;
                    probability[city[j].u] += comsat * probability[u];
                }
                superpass[u] = comsat;
            }
    
            // calculate remaining probability
            for (int i=0; i<n; i++)
                remainprob[i] = 0;
            for (int i=0; i<n-1; i++) {
                int temp = i;
                while(temp < n-1) {
                    temp = prevnode[temp];
                    remainprob[temp] += superpass[i] * probability[i];
                }
            }
            for (int i=0; i<n; i++)
                probability[i] += remainprob[i];
    
            //output
            scanf("%d", &q);
            while(q--) {
                scanf("%d", &b);
                printf("%.8f ", probability[b-1]);
            }
            printf("\n");
        }
    
        return 0;
    }
    

    10년 전
3개의 댓글이 있습니다.
  • Taeyoon_Lee
    Taeyoon_Lee

    시간복잡도가 O(N^2)가 되면 TLE가 날 겁니다. N이 10000이나 되기 때문이지요. 우선 Dijkstra를 더 빠른 방식으로 구현하셔야 합니다.(JMBook를 참고하세요!) 확률 계산 또한 O(N^2logN) 보다 빠른 방식을 써야 하는데.....

    더블린에서 가장 먼 여행지부터 계산해나가면 O(N)에 계산할 수 있습니다.


    10년 전 link
  • veckal
    veckal

    답변 감사합니다.
    그런데 확률 계산에서 각 정점마다 갈 수 있는 후보지를 계산해서 정렬하는데 nlogn 타임이 들지 않나요? 더블린에서 가장 먼 여행지부터 계산해도 n*nlogn 이라서 n^2logn이 되는거 같은데..


    10년 전 link
  • Taeyoon_Lee
    Taeyoon_Lee

    정렬하는 부분은 nlogn이 맞습니다. O(N)은 제가 실수했네요. O(N+M)이 맞습니다.(물론 정렬까지 생각하면 O(NlogN + M)) 각 여행지에 대해 계산할 때, 붙어있는 에지 수만큼 계산이 필요하기 때문이지요.


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