优化BFS的实施

Optimizing an implementation of BFS

本文关键字:BFS 优化      更新时间:2023-10-16

我正在学习Graph的基础知识,并从
开始解决问题https://www.hackerrank.com/challenges/bfsshortreach.代码运行良好,但我得到了一个测试用例的TLE。我把cin/cout改成了printf/scanf,希望它能被接受,但没有成功。到目前为止,我的代码是

#include <iostream>
#include <queue>
#include <climits>
#include <stdio.h>
#include <queue>
#include <list>
#include <vector>
struct Graph
{
    int size;
    std::list<int> *adj;
};
Graph* createGraph(int size)
{
    Graph *graph = new Graph();
    graph->size = size;
    graph->adj = new std::list<int>[size];
    return graph;
}
void addEdge(Graph *graph, int source, int dest)
{
    graph->adj[source].push_back(dest);
    graph->adj[dest].push_back(source);
}
void printGraph(Graph *graph)
{
    for (int i = 0; i < graph->size; ++i)
    {
        for(std::list<int>::iterator it = graph->adj[i].begin(); it!= graph->adj[i].end(); ++it)
          {
            std::cout<<*it<<' ';
          }
          std::cout<<std::endl;
    }
}
void BFS(Graph *graph, int src)
{
    std::queue <int> nodes;
    std::vector<bool> v(graph->size,false);
    std::vector<int> distance(graph->size, INT_MAX);
    v[src] = true;
    distance[src] = 0;
    nodes.push(src);
    std::list<int>::iterator it;
    while(!nodes.empty())
    {
        int temp = nodes.front();
        v[temp] = true;
        nodes.pop();
        for(it = graph->adj[temp].begin(); it!= graph->adj[temp].end(); ++it)
          {
            if(!v[*it])
            {
                nodes.push(*it);
                int current = distance[temp] != INT_MAX? distance[temp] : 0;
                distance[*it] = std::min(current + 6, distance[*it]);
            }
          }
    }
    for (int i = 0; i < distance.size(); ++i)
    {
        int dist = distance[i] != INT_MAX ?  distance[i] : -1;
        if(i!= src)
        {
            printf("%d ", dist);
        }
    }
        printf("n");
}
int main(int argc, char const *argv[])
{
    int T;
    scanf(" %d", &T);
    while(T--) {
        int n, m, s;
        // cin>>n>>m;m
        scanf(" %d %d", &n, &m);
        Graph *graph = createGraph(n);
        while(m--)
        {
            int x, y;
            // cin>>x>>y;
            scanf(" %d %d", &x, &y);
            addEdge(graph, x-1, y-1);
        }
        // cin>>s;
        scanf(" %d", &s);
        BFS(graph, s-1);
        // printGraph(graph);
    }
    return 0;
}

我相信CCD_ 1。并且插入边所需的时间复杂度是 O(1) 。所以AFAIK,这是我们能做的最好的事情(也许?)。我不确定这是否是存储图形的最佳方式。任何更好、更快的存储图形的方法和改进建议都将非常棒。

这不是优化的问题。您应该在将队列true中的每个节点放入queue后立即设置它们的visited,否则您将多次重新访问某些节点。您将一个node放入队列中,但没有将其"已访问"设置为true,并将其延迟到将该节点从队列中取出,然后将其"访问"设置成true。那么会发生什么呢?考虑这个图V={a,b,c,d}E={a->b, a->c, a->d, b->d, c->d}。第一个CCD_ 10在队列中推送CCD_。然后O(m log n) 2将d推送到队列,之后c也将d推送到队列。所以您的队列看起来像q={d,d,d}。因此,您将访问d三次。这是一个非常小的案例,你可以看到,对于大的案例,这怎么会导致一个大问题。

类似这样的东西:

queue <int> q;
q.push(source);
visited[source] = true;
while ( q.size() ){
    int current_node = q.front();
    q.pop();
    for ( int i=0; i<adjacencyList[current_node].size(); ++i ){
        int next_node = adjacencyList[current_node][i];
        if ( visited[next_node] )
            continue;
        dist[next_node] = dist[current_node] + 1;
        visited[next_node] = 1;
        q.push(next_node);
    }
}