【问题标题】:algorithm graph fiber network skeleton算法图纤维网络骨架
【发布时间】:2020-11-28 08:46:41
【问题描述】:

我有一个练习要做纤维网络骨架。每个节点都由 IP 地址表示。在输入时,我得到构建网络的命令 (B),然后是检查 (T) 一个节点与另一个节点之间是否存在连接的命令。

  • B 100.100.100.1 100.100.100.2
  • B 100.100.100.1 100.100.100.3
  • B 100.100.100.10 100.100.100.11
  • T 100.100.100.1 100.100.100.3
  • T 100.100.100.10 100.100.100.2
  • T 100.100.100.10 100.100.100.11
  • B 100.100.100.11 100.100.100.2
  • T 100.100.100.10 100.100.100.3
  • T 100.100.100.100 100.100.100.103

对于每个 T 命令我必须回答:是或否。所以在这个例子中,它将是:Y N Y Y N。 我有很好的结果,但我的解决方案因执行时间而失败 - 我在这里查看:https://pl.spoj.com/problems/TFIBRE/

我的代码(已编辑):

#include <iostream>
#include <string>
#include <unordered_map>
#include <list>
#include <set>
#include <arpa/inet.h>

using namespace std; 
class Graph 
{ 
    std::unordered_map<uint32_t, bool> visited;
    std::unordered_map<uint32_t, set<uint32_t>> adj; 

    bool DFSUtil(const uint32_t& v, const uint32_t&, std::unordered_map<uint32_t, bool>& visited); 
public:
    
    Graph(): visited{}, adj{}
    {}
    
    void addEdge(const uint32_t& v, const uint32_t& w); 
    bool DFS(const uint32_t& v, const uint32_t& el);
}; 

void Graph::addEdge(const uint32_t& v, const uint32_t& w) 
{ 
    adj[v].insert(w);
    adj[w].insert(v);
} 
  
bool Graph::DFSUtil(const uint32_t& v, const uint32_t& el, std::unordered_map<uint32_t, bool>& visited) 
{ 
    if (v == el){
        return true;
    }

    visited[v] = true; 

    set<uint32_t>::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i)
        if (!visited[*i]){
            if(DFSUtil(*i, el, visited))
                return true;
            else
                continue;
        }
    return false;
} 
  
bool Graph::DFS(const uint32_t& v, const uint32_t& el) 
{ 
    visited.clear();
    
    for (std::pair<uint32_t, set<uint32_t>> element : adj)
        visited[element.first] = false;

    return DFSUtil(v, el, visited); 
}

int main() 
{ 
    Graph g;
    char command;
    char addr1[16];
    char addr2[16];
    
    in_addr ip1;
    in_addr ip2;

    
    while (scanf("%c %s %s ", &command, addr1, addr2) == 3)
    {        
        inet_aton(addr1, &ip1);
        inet_aton(addr2, &ip2);
        
        if (command == 'B')
            g.addEdge(ip1.s_addr, ip2.s_addr);
        else
            cout << (g.DFS(ip1.s_addr, ip2.s_addr) ? "T\n" : "N\n");
    }
    return 0; 
} 

搜索花费的时间最长。我能做些什么来改善这一点?也许我不应该使用 stl 容器?但那该用什么?

【问题讨论】:

  • 询问有关如何改进工作代码的想法通常指向codereview。如果你在这里没有命中,你可以在那里尝试。
  • 也许我不应该使用 stl 容器? -- 为什么这么快就责怪 STL 容器?也许是您正在使用的算法或数据结构?或者您可能在不必要地复制大型对象?

标签: c++ algorithm graph


【解决方案1】:

如果链接是双向的并且对距离没有限制,您可以尝试使用 https://en.wikipedia.org/wiki/Disjoint-set_data_structure(也称为 Union-Find)。当您看到一个链接时,合并拥有该链接两端的集合。要测试连通性,请查看两端是否已合并到同一个集合中。

【讨论】:

  • 我能够通过 union-find 的所有测试,谢谢!
【解决方案2】:

一个明显的问题是您多次不必要地分配内存。

首先为每一行创建一个新的std::vector&lt;std::string&gt; words;,这是毫无意义的,因为你知道每一行都有三个单词。所以你可以这样做:

char command; // B or T
char addr1[16];
char addr2[16];
while (scanf("%c %s %s", &command, addr1, addr2) == 3)
{
    if (command == 'B')
        g.addEdge(addr1, addr2);
    else
        cout << g.DFS(addr1, addr2) ? "Y\n" : "N\n";
}

请注意,我还删除了您对 endl 的使用,这很慢,因为它每次都会强制刷新缓冲区。

继续我的工作,从您的代码中删除更多分配。例如,您的 DFS() 每次都会创建一个新的 unordered_map,这是完全没有必要的,它可以每次都使用同一个映射,然后 clear() 它,重用相同的分配内存。当您知道字符串始终在 8 到 16 个字节之间(包括空终止符)时,使用 std::string 毫无意义。

连这一行都分配了内存!

for (std::pair<std::string, set<std::string>> element : adj)

它应该使用一个引用,而不是每个值的副本:

for (auto& element : adj)

【讨论】:

  • 我编辑了我的代码并在上面发布,不幸的是修复不足,我的代码仍然无法执行时间。
猜你喜欢
  • 1970-01-01
  • 2012-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多