HackerRank上的道路和图书馆(DFS)超时

时间:2017-09-01 17:30:38

标签: javascript algorithm dfs

我知道已经存在这样一个问题,但答案并没有真正解决我的问题,因为我似乎已经实施了它,但它仍然超时。

HackerRank上的任务是here

主要思想是在图中找到“连通分量”(即相互连接的节点组)。具体来说,计算有多少节点,以及每个节点中有多少个节点。我正在使用一个简单的数组:connectedComponents[index] = numberOfNodesForAComponentAtIndex

问题在于我的解决方案因大量输入而超时,但对于较小的输入会产生正确的结果。

我想帮助了解我的代码的哪一部分可以更快。

function calculateCost(n, m, cLib, cRoad, roads) {
    // cost of road >= cost of library?
    if (cRoad >= cLib) {
        // build a library in each city
        return n * cLib;
    }

    // cost of road < cost of library?
    // find connected components: build a library in only 1, and connect all others with roads

    // infos needed:
    // 1) how many connected components
    // 2) how many cities in each connected component

    // array of numbers : each number represents the number of cities in connected component at index
    var connectedComponents = calculateConnectedComponents(n, m, roads);

    var cost = 0;   

    for (var i = 0; i < connectedComponents.length; i++) {
        var cc  = connectedComponents[i];
        cost += cLib + (cc - 1) * cRoad;
    }

    return cost;
}


function calculateConnectedComponents(n, m, roads) {
    // array of numbers : each number represents the number of cities in connected component at index
    var connectedComponents = [];

    // initialize all cities to not visited
    var notExpanded = new Set();
    var cities = [];

    for (var i = 1; i <= n; i++) {
        notExpanded.add(i);
        cities[i-1] = i;
    }

    var expansions = calculateExpansions(roads);

    while (notExpanded.size > 0) {
        // DFS
        var stack = [];

        // move on to the next city
        var start = getNextCity(cities);
        stack.push(start);


        // mark visited
        notExpanded.delete(start);
        cities[start-1] = -1;

        // calculate connected component
        var cc = 0;
        while (stack.length > 0) {
            process.stdout.write("STACK: " + stack.toString() + "\n");
            var city = stack.pop();   

            process.stdout.write("City: " + city.toString() + "\n");

            cc ++;

            // mark visited
            cities[city-1] = -1;

            var expanded = expand(city, expansions);
            process.stdout.write("EXP: " + expanded.toString() + "\n\n");

            for (var i = 0; i < expanded.length; i++) {
                if (notExpanded.has(expanded[i])) {
                    notExpanded.delete(expanded[i]);
                    stack.push(expanded[i]);
                }        
            }
        }

        connectedComponents.push(cc);
    }

    return connectedComponents;
}

function calculateExpansions(roads) {
    var expansions = {};

    for (var i = 0; i < roads.length; i++) {
        var road = roads[i];

        if (!(road.c1 in expansions)) {
            var exp = [];
            exp.push(road.c2);
            expansions[road.c1] = exp;
        } else {
            expansions[road.c1].push(road.c2);
        }

        if (!(road.c2 in expansions)) {
            var exp = [];
            exp.push(road.c1);
            expansions[road.c2] = exp;
        } else {
            expansions[road.c2].push(road.c1);
        }
    }

    return expansions;
}

function expand(city, expansions) {    
    if (expansions[city]) {
        return expansions[city];
    } else {
        return [];
    }
}


function getNextCity(cities) {
    for (var i = 0; i < cities.length; i ++) {
        if (cities[i] !== -1) {
            return cities[i];
        }
    }

    // error, should not happen
    return -1;
}

function main() {
    var q = parseInt(readLine());

    var costs = [];


    for(var a0 = 0; a0 < q; a0++){

        var n_temp = readLine().split(' ');
        var n = parseInt(n_temp[0]);
        var m = parseInt(n_temp[1]);
        var x = parseInt(n_temp[2]);
        var y = parseInt(n_temp[3]);

        var roads = [];

        for(var a1 = 0; a1 < m; a1++){
            var city_1_temp = readLine().split(' ');
            var city_1 = parseInt(city_1_temp[0]);
            var city_2 = parseInt(city_1_temp[1]);

            var road = {
                c1 : city_1,
                c2 : city_2
            };

            roads.push(road);
        }

        // n : number of cities
        // m : number of roads
        // x : cost of the library
        // y : cost of the road
        // roads: road connections
        costs.push(calculateCost(n, m, x, y, roads));   
    }

    process.stdout.write(costs.join("\n").toString());
}

1 个答案:

答案 0 :(得分:1)

看起来可能很慢的一件事是getNextCity。

如果图中没有道路,那么你将调用getNextCity n次,每次都是O(n)次操作,因此整体复杂度为O(n ^ 2)。

改善这种情况的一种方法是仅从找到的最后一个城市进行搜索,而不是每次从0开始。这会将该部分的复杂性从O(n ^ 2)降低到O(n),因为每个城市只会被测试一次。