我知道已经存在这样一个问题,但答案并没有真正解决我的问题,因为我似乎已经实施了它,但它仍然超时。
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());
}
答案 0 :(得分:1)
看起来可能很慢的一件事是getNextCity。
如果图中没有道路,那么你将调用getNextCity n次,每次都是O(n)次操作,因此整体复杂度为O(n ^ 2)。
改善这种情况的一种方法是仅从找到的最后一个城市进行搜索,而不是每次从0开始。这会将该部分的复杂性从O(n ^ 2)降低到O(n),因为每个城市只会被测试一次。