2016-09-16 1 views
4

첫째, 어떤 알고리즘이 호출되는지, 우선적 인 문제인지는 확실하지 않습니다. 질문의 첫 번째 부분은이 알고리즘이 무엇입니까? [[1, 2, 4, 6], [3], [5], [7], [8, 9, 10]]비순환 지향 그래프가 주어지면 "동일한 레벨에있는"노드 컬렉션 모음을 반환합니까?

편집 : : 저를 추가하자 기본적으로

내가 노드 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]과 가장자리이에서 ([1,3],[2,3],[3,5],[4,5],[5,7],[6,7],[7,8],[7,9],[7,10])

는 다음과 같이 컬렉션을받을 수 있는지 궁금 해요를 삽입하는에 DiGraph()이 도움이된다면 약간의 제약. 이 -이이 보장, 더 사이클이 없습니다 - 아무도 그래프에 대한 포인트를 시작하지 있습니다

난 할 노력하고있어, 자신의 처리를 병렬화 할 수 있도록 동일한 수준에서 노드를 수집하는 것입니다하지만, 외부 컬렉션 내에서 처리는 연속적입니다.

EDIT2 : "레벨"을 표현하는 가장 쉬운 방법은 의 가장 깊은 전임자인데, 전임자와 동일한 깊이를 가진 모든 노드입니다. 따라서 위의 목록에서 첫 번째 항목은 가장 깊은 선행자로 0을 갖고 두 번째 노드는 1을 가지며 세 번째 노드는 두 개를 갖는 노드입니다. 각 목록 내에서 형제 인의 순서는 병행 처리되므로 관련이 없습니다.

+0

* BFS *, Breadth First Search? https://en.wikipedia.org/wiki/Breadth-first_search –

+0

당신이 요구하는 것은 그래프 구조에 대해 여러 가지 가정을하는 것처럼 보입니다 (예를 들어 어떤 노드에서 어떤 노드로든 하나의 경로 만이 존재한다는 것) 다른 노드). '[1, 2] '엣지를 그래프에 추가하면 콜렉션이 어떻게 되겠습니까? – BrenBarn

+0

질문의 의도를보다 정확하게 반영하기 위해 제목을 수정했습니다. 희망을 나는 오해하지 않았다 ... – holdenweb

답변

4

이 그래프의 출력을 [[1, 2, 4, 6], [3], [5], [7], [8, 9, 10]]으로 지정하고 싶습니다. IIUC의 패턴은 다음과 같습니다.

  • [1, 2, 4, 6]은 가장자리가없는 노드입니다.

  • [3]은 모든 이전 노드가 삭제되었다고 가정하고 가장자리에 없음이없는 노드입니다.

  • [4]은 모든 이전 노드가 삭제되었다고 가정 할 때 가장자리에 없음이없는 노드입니다.

  • 등 (모든 노드가 삭제 될 때까지)

우리가 그런

g = networkx.DiGraph() 
g.add_edges_from([[1,3],[2,3],[3,5],[4,5],[5,7],[6,7],[7,8],[7,9],[7,10]]) 

로 시작하는 말 우리가 할 수있는

def find_levels(g): 
    levels = [] 
    while g.nodes(): 
     no_in_nodes = [n for (n, d) in g.in_degree(g.nodes()).items() if d == 0] 
     levels.append(no_in_nodes) 
     for n in no_in_nodes: 
      g.remove_node(n) 
    return levels 

우리가 실행하는 경우처럼 코드이 결과는 다음과 같습니다.

>>> find_levels(g) 
[[1, 2, 4, 6], [3], [5], [7], [8, 9, 10]] 

여기서 복잡도는 Θ (| V | + | E |). Fibonnacci Heap을 사용하면 다소 복잡한 버전을 구축 할 수 있습니다.기본적으로 모든 꼭지점은 힙에 배치해야하며 각 레벨은 0 도의 꼭지점으로 구성됩니다. 하나가 터지면 다른 꼭지점의 가장자리가 제거 될 때마다 힙 감소 키 작업으로 변환 할 수 있습니다 (나머지 꼭지점의 도수가 감소됨). 이렇게하면 실행 시간이 Θ (| V | log (| V |) + | E |)으로 줄어 듭니다.

+0

여기서 문제는 노드를 제거 할 수 없다는 것입니다. 예를 들어 '1'을 보면 "level" 3/5/7이 변경됩니다 .. – Nim

+0

@Nim 나는 귀하의 요지를 봅니다. 업데이트를 참조하십시오. –

+0

그 주셔서 감사합니다,하지만, 나는 그것을 나타내는 수준의 각 노드에 속성을 유지하는 것입니다 약간 다른 접근 방식을 결정했습니다. 새로운 노드를 추가하고 트리를 재정렬하면 후임을 걸어 최대 깊이를 추적합니다. 같은 종류의 찰스의 답변을 아래에 있습니다. 일반적으로 이러한 작업은 매우 드물게 수행되어야합니다. 가장 일반적인 작업은 트리를 평가하는 것이고 두 번째 방법은 너무 비싸다. 토폴로지 종류에 따라 트리를 한 번 지나치게하면 속성에서 보았을 때 내가 필요한 것을 정확하게 수행 할 수있게된다. – Nim

0

왜 bfs가이를 해결하지 못합니까? bfs 알고리즘은 광폭 트래버 설 알고리즘, 즉 트리 레벨을 가로 지르는 알고리즘이다. 이것은 또한 같은 레벨에있는 모든 노드가 한 번에 탐색된다는 것을 의미합니다. 이는 원하는 출력입니다. 주석에서 지적했듯이 이것은 그래프의 시작점을 가정합니다.

+1

BFS에 관한 한 가지는 시작 노드를 가정하는 것인데,이 노드 세트를 전체적으로 그래프에 대한 정보로 가져 오는 것이 좋습니다. – BrenBarn

+0

@brenbarn : 먼저 G의 모든 노드와 에지로 구성되는 그래프 G '를 작성하고, G의 모든 노드 q에 대해 에지 n'-> q 인 새로운 노드 n '을 in-degree 0으로 작성하십시오. O (| E + N |)에서 모든 q에 대해 n '-> q를 더한 다음 모든 모서리를 통과시키고 추가 된 모서리 세트에서 모서리의 머리를 제거합니다.) 모서리 addes가없는 경우, 그래프는 주기적이며 노드의 "레벨"개념은 약간 이상합니다. 그러나 Tarjan의 알고리즘을 사용하여 SCC를 식별 한 다음 SCC 유도 그래프에서 확대 그래프를 작성할 수 있습니다. – rici

+1

당신은 BFS로 할 수 있지만 대답이 암시하는 것처럼 간단하지는 않습니다. 특히, "같은 레벨에있는 모든 노드가 한 번에 통과됩니다"*라는 문장은 거짓입니다. 예를 들어, 노드 7에 도달하는 여러 가지 방법이 있습니다. 가능한 경로는 {1,3,5,7}, {2,3,5,7}, {4,5,7} 및 {6,7 }. 그래서 BFS는 레벨 2,3과 4에서 노드 7을 찾을 것입니다. 노드 7의 올바른 레벨은 4입니다. 따라서 BFS는 노드가 발견 된 가장 깊은 레벨을 추적해야합니다. (물론 이미 언급했듯이 BFS를 시작하기 전에 시작 노드를 찾아야합니다.) – user3386109

2

토폴로지 정렬은 Ami 상태와 같이이를 달성합니다. 다음은 컨텍스트가없는 부스트 그래프 라이브러리 구현이지만 의사 코드는 추출 할 수 있습니다. toporder 객체는 토폴로지 순서에 반복기를 제공합니다. 원하는 경우 일반 알고리즘을 추출 할 수 있습니다.

template<typename F> 
void 
scheduler<F>::set_run_levels() 
{ 

    run_levels = std::vector<int>(tasks.size(), 0); 
    Vertexcont toporder; 

    try 
    { 
     topological_sort(g, std::front_inserter(toporder)); 
    } 
    catch(std::exception &e) 
    { 
     std::cerr << e.what() << "\n"; 
     std::cerr << "You most likely have a cycle...\n"; 
     exit(1); 
    } 

    vContIt i = toporder.begin(); 

    for(; 
     i != toporder.end(); 
     ++i) 
    { 
     if (in_degree(*i,g) > 0) 
     { 
      inIt j, j_end; 
      int maxdist = 0; 
      for(boost::tie(j,j_end) = in_edges(*i,g); 
       j != j_end; 
       ++j) 
      { 
       maxdist = (std::max)(run_levels[source(*j,g)], maxdist); 
       run_levels[*i] = maxdist+1; 
      } 
     } 
    } 
} 

같은 문제에이 문제를 적용한 다음 불필요하다고 생각했습니다. 모든 작업이 자신의 부양 가족에게 완료를 알리면 (condition_variable, promise에 의해) 헤어 트리거에 대한 작업을 설정하기 만하면됩니다. 따라서 필요한 것은 각 작업의 종속성을 파악하고 초기 작업을 찾은 다음에 시작하는 것입니다. 귀하의 경우에는 run_level의 전체 사양이 필요합니까?

+0

흥미 롭습니다! 질문은'networkx'로 태그가 붙었지만 여러분의 코드를 살펴보고 BGL에서이 작업을 수행하는 방법을 기대하고 있습니다. –

+0

트리에서 너무 많은 상태를 피하려고했지만 토폴로지 종류와 결합 된 run_level을 보유하고있는 것처럼 보인다고해서 단일 패스에서 트리를 처리하는 데 도움이됩니다. 그런 다음 설명 할 때 카운트 다운 래치가 필요하지 않습니다. 다음 실행 레벨에 도달하면 이전에 모든 노드가 평가되었습니다. – Nim

관련 문제