58 class EdgeWeightedGraph;
278 m_originalGraph = &G;
279 m_originalTerminals = &terminals;
281 m_upperBound = MAX_WEIGHT;
283 m_mapping.init(m_graph);
284 m_terminals.reset(
new NodeSet<>(m_graph));
285 int nodeCount = m_originalGraph->numberOfNodes();
286 m_edges =
Array2D<edge>(0, nodeCount, 0, nodeCount,
nullptr);
290 for (
node v : m_originalGraph->nodes) {
291 node copiedNode = m_graph.newNode();
292 copiedNodes[v] = copiedNode;
295 for (
edge e : m_originalGraph->edges) {
298 newEdge(source, target, e);
301 for (
node v : *m_originalTerminals) {
302 setTerminal(copiedNodes[v],
true);
306 T result = solve(chosenEdges);
311 for (
edge e : chosenEdges) {
321 if (finalSteinerTree->
copy(v) ==
nullptr) {
324 if (finalSteinerTree->
copy(w) ==
nullptr) {
327 finalSteinerTree->
newEdge(e, m_originalGraph->weight(e));
335 T result = MAX_WEIGHT;
340 OGDF_ASSERT(m_mapping[e]->graphOf() == m_originalGraph);
341 result = m_originalGraph->weight(m_mapping[e]);
349 for (
edge e : m_graph.edges) {
351 OGDF_ASSERT(m_mapping[e]->graphOf() == m_originalGraph);
368 edge result = m_mapping[e];
378 edge result = m_graph.newEdge(source, target);
379 m_mapping[result] = e;
380 setEdgeLookup(source, target, result);
389 setEdgeLookup(v, e->
target(), e);
390 m_graph.moveSource(e, v);
397 setEdgeLookup(e->
source(), v, e);
398 m_graph.moveTarget(e, v);
403 return m_terminals->isMember(v);
409 m_terminals->insert(v);
411 m_terminals->remove(v);
417 m_chosenEdges.clear();
419 m_recursionDepth = 0;
421 T result = bnbInternal(0, tmp);
423 for (
edge e : m_chosenEdges) {
432 edge result =
nullptr;
436 T sumOfMinWeights = 0;
437 T sumOfMinTermWeights = 0;
438 T absoluteMinTermWeight = MAX_WEIGHT;
440 sumOfMinWeights < MAX_WEIGHT && it.
valid(); ++it) {
442 T minTermWeight = MAX_WEIGHT, minWeight = MAX_WEIGHT, secondMinWeight = MAX_WEIGHT;
443 edge minEdge =
nullptr;
448 edge e = adj->theEdge();
449 if (weightOf(e) < minWeight) {
450 secondMinWeight = minWeight;
451 minWeight = weightOf(e);
454 if (weightOf(e) < secondMinWeight) {
455 secondMinWeight = weightOf(e);
459 if (isTerminal(adj->twinNode()) && weightOf(e) < minTermWeight) {
460 minTermWeight = weightOf(e);
461 if (minTermWeight < absoluteMinTermWeight) {
462 absoluteMinTermWeight = minTermWeight;
467 if (sumOfMinTermWeights < MAX_WEIGHT && minTermWeight < MAX_WEIGHT) {
468 sumOfMinTermWeights += minTermWeight;
470 sumOfMinTermWeights = MAX_WEIGHT;
472 OGDF_ASSERT(absoluteMinTermWeight <= sumOfMinTermWeights);
476 if (minWeight == MAX_WEIGHT || secondMinWeight == MAX_WEIGHT) {
478 if (minWeight == MAX_WEIGHT) {
479 sumOfMinWeights = MAX_WEIGHT;
482 sumOfMinWeights += minWeight;
484 T penalty = secondMinWeight - minWeight;
485 if (penalty > maxPenalty) {
486 maxPenalty = penalty;
493 if (result !=
nullptr) {
494 T maxCost = m_upperBound - prevCost;
495 if (sumOfMinTermWeights < MAX_WEIGHT) {
496 sumOfMinTermWeights -= absoluteMinTermWeight;
498 if (maxCost <= sumOfMinWeights && maxCost <= sumOfMinTermWeights) {
508 T result = MAX_WEIGHT;
511 #ifdef OGDF_MINSTEINERTREE_SHORE_LOGGING
515 if (prevCost <= m_upperBound) {
516 if (m_terminals->size() < 2) {
518 if (prevCost != m_upperBound || m_chosenEdges.empty()) {
522 m_upperBound = prevCost;
525 edge branchingEdge = determineBranchingEdge(prevCost);
526 T branchingEdgeWeight = weightOf(branchingEdge);
528 #ifdef OGDF_MINSTEINERTREE_SHORE_LOGGING
529 for (
int i = 0; i < m_recursionDepth; i++) {
532 std::cout <<
"branching on edge: " << branchingEdge << std::endl;
535 if (branchingEdgeWeight < MAX_WEIGHT) {
542 nodeToRemove = branchingEdge->
target();
543 targetNode = branchingEdge->
source();
547 edge origBranchingEdge = deleteEdge(branchingEdge);
558 while (m_graph.searchEdge(targetNode, nodeToRemove) !=
nullptr) {
559 edge e = m_graph.searchEdge(targetNode, nodeToRemove);
565 while (m_graph.searchEdge(nodeToRemove, targetNode) !=
nullptr) {
566 edge e = m_graph.searchEdge(targetNode, nodeToRemove);
573 OGDF_ASSERT(m_graph.searchEdge(targetNode, nodeToRemove) ==
nullptr);
574 OGDF_ASSERT(m_graph.searchEdge(nodeToRemove, targetNode) ==
nullptr);
578 adjNext = adj->
succ();
579 edge e = adj->theEdge();
585 edge f = lookupEdge(targetNode, adj->twinNode());
586 bool deletedEdgeE =
false;
588 if (weightOf(f) < weightOf(e)) {
603 if (e->
target() == nodeToRemove) {
606 moveTarget(e, targetNode);
611 moveSource(e, targetNode);
620 bool targetNodeIsTerminal = isTerminal(targetNode),
621 nodeToRemoveIsTerminal = isTerminal(nodeToRemove);
623 OGDF_ASSERT(targetNodeIsTerminal || nodeToRemoveIsTerminal);
624 setTerminal(nodeToRemove,
false);
625 setTerminal(targetNode,
true);
627 #ifdef OGDF_MINSTEINERTREE_SHORE_LOGGING
628 for (
int i = 0; i < m_recursionDepth; i++) {
631 std::cout <<
"inclusion branch" << std::endl;
634 currentEdges.
pushFront(origBranchingEdge);
635 result = bnbInternal(branchingEdgeWeight + prevCost, currentEdges);
636 OGDF_ASSERT(currentEdges.front() == origBranchingEdge);
642 setTerminal(nodeToRemove, nodeToRemoveIsTerminal);
643 setTerminal(targetNode, targetNodeIsTerminal);
646 while (!movedEdges.empty()) {
649 edge e = lookupEdge(v, targetNode);
654 moveTarget(e, nodeToRemove);
656 moveSource(e, nodeToRemove);
661 while (!delEdges.empty()) {
667 newEdge(source, target, origDelEdges.
popFrontRet());
671 #ifdef OGDF_MINSTEINERTREE_SHORE_LOGGING
672 for (
int i = 0; i < m_recursionDepth; i++) {
675 std::cout <<
"exclusion branch" << std::endl;
678 T exEdgeResult = bnbInternal(prevCost, currentEdges);
681 if (exEdgeResult < result) {
682 result = exEdgeResult;
686 newEdge(nodeToRemove, targetNode, origBranchingEdge);
700 m_graph.allNodes(nodes);
702 for (
node v : nodes) {
704 copiedIsTerminal[v] = isTerminal(v);
707 m_graph.allEdges(edges);
708 for (
edge e : edges) {
709 copiedGraph.
newEdge(e, weightOf(e));
711 std::stringstream filename;
712 filename <<
"bnb_internal_" << m_recursionDepth <<
".svg";
713 this->drawSteinerTreeSVG(copiedGraph, copiedIsTerminal, filename.str().c_str());