You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

大规模无环图路径人口统计的低时间复杂度算法选型咨询

城市网络路径人口查询的高效算法方案选择

问题描述

给定一个无环城市网络(树结构),包含N个城市,每个城市拥有唯一ID(取值范围1至N),任意两城市间存在且仅存在一条唯一路径,各城市的人口数据已知。需处理Q次查询,每次查询需返回从节点U到节点V的路径上,人口数值小于等于W的城市数量。

示例:当N=3,人口数组为[1,2,3],城市连接为[[1,2],[2,3]],查询[1,3,2]时,路径上符合条件的城市数量为2(城市1和城市2)。

原DFS实现代码

原方案采用DFS遍历路径统计符合条件的城市,但仅适用于N较小的场景:

int *city_population(int N, int *population, int **road, int Q, int **cities)
{
    int *city_count = (int *)calloc(Q, sizeof(int));
    int *path = (int *)calloc(N, sizeof(int));
    int *visited = (int *)calloc(N, sizeof(int));
    int u, v, w, pathIdx, pathFound, count;

    for (int i = 0; i < Q; i++)
    {
        pathIdx = 0;
        pathFound = 0;
        count = 0;

        // u is the starting node
        u = cities[i][0];
        // v is the stopping node
        v = cities[i][1];
        // w is the max population
        w = cities[i][2];

        DFS(N, u - 1, v, population, visited, road, path, &pathIdx, &pathFound);

        if (pathFound)
        {
            for (int j = 0; j < pathIdx; j++)
            {
                if (population[path[j]] <= w)
                    count++;
            }
        }

        city_count[i] = count;

        reset_array(visited, N);
        reset_array(path, N);
    }

    free(path);
    free(visited);

    return city_count;
}

void DFS(int N, int startIdx, int stopIdx, int *population, int *visited, int **road, int *path, int *pathIdx, int *pathFound)
{
    int connection;

    visited[startIdx] = 1;
    path[*pathIdx] = startIdx;
    (*pathIdx)++;

    if (startIdx + 1 == stopIdx)
    {
        *pathFound = 1;
        return;
    }

    for (int i = 0; i < N - 1 && !*pathFound; i++)
    {
        connection = road[i][1];
        if (road[i][0] == startIdx + 1 && !visited[connection - 1])
            DFS(N, connection - 1, stopIdx, population, visited, road, path, pathIdx, pathFound);

        else
        {
            connection = road[i][0];
            if (road[i][1] == startIdx + 1 && !visited[connection - 1])
                DFS(N, connection - 1, stopIdx, population, visited, road, path, pathIdx, pathFound);
        }
    }

    if (!*pathFound)
        (*pathIdx)--;

    visited[startIdx] = 0;
}

void reset_array(int *arr, int size)
{
    for (int i = 0; i < size; i++)
        arr[i] = 0;
}

现有方案的瓶颈

原DFS方案的时间复杂度为O(Q*N):每次查询都需要遍历U到V的路径(最坏情况遍历整个树),当N达到105量级时,Q次查询的总运算量会达到1010级别,完全超出时间限制。

三种方案对比与最优选择

1. 实现Breadth-First-Search(BFS)

BFS仅改变了路径遍历的顺序,本质和DFS一样,单次查询的时间复杂度仍为O(N),总复杂度还是O(Q*N),无法解决大规模数据的性能问题,直接排除。

2. 优化road二维数据结构

原代码中用二维数组存储边,每次找邻接节点需要遍历所有N-1条边(O(N)时间),优化为邻接表可以将邻接节点的查询时间降到O(1),但这只是优化了遍历的常数项,整体时间复杂度依然是O(Q*N),对于10^5量级的N和Q来说,依然无法承受,不是最优解。

3. 使用Heavy-Light Decomposition(重链剖分)

这是解决树路径查询问题的经典高效方案,能从根本上降低时间复杂度:

  • 预处理阶段:O(N log N)时间完成树的重链剖分,将树分解为若干条连续的重链,同时构建支持区间统计的线段树(每个区间存储人口值的有序列表,用于快速查询≤W的元素数量)。
  • 查询阶段:将U到V的路径拆分为若干段重链上的连续区间,对每个区间执行O(log N)的统计查询,单次查询总时间复杂度为O((log N)^2)。

这种方案完全适配N和Q达到10^5量级的场景,是三者中唯一能满足性能要求的方案。

另外,也可以结合树上倍增求LCA(最近公共祖先)+ 主席树的方案,实现O(N log N)预处理、O(log N)单次查询的性能,也是可行的,但重链剖分的实现逻辑相对直观,适合这类路径统计需求。


内容的提问来源于stack exchange,提问作者Centauri85

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:44:58