排列数字对,使相邻对的成员相等

时间:2016-09-04 17:33:07

标签: algorithm sorting

我想安排以下项目,从12-8开始形成最长的链条,并从头到尾匹配数字。

我的项目是7-4,11-8,11-11,1-0,4-2,7-5,10-8,7-3,10-5,7-2,9-8, 12-8,0-0,11-10

可能最长的链是12-8,8-11,11-11,11-10,10-5,5-7,7-4,4-2,2-7,7-3

我尝试迭代项目数组并获取与我寻找的数字匹配的第一个值,但它不会产生最长的链。我的方法让我:12-8,8-11,11-11,11-10,10-8,8-9

如何为此任务编写正确的排序算法?

5 个答案:

答案 0 :(得分:2)

你需要递归,但它可能不适用于更大的数据集: 这样的事情。

免责声明:这可能不是最优化的解决方案(复杂度O(N!))但如果允许使用递归则实现起来非常简单

(这不是客观的c代码,它是一种算法,自己翻译,抱歉我不知道目标-c)

list function sortTupleList(list a, list b) //b is the current list
  list biggest = newlist()
  int target = b.last()[1]
  for(tuple k in a)
    if (k[0] == target)
      list n = sortTupleList(a.remove(k), b.add(k))
      if(n.size > biggest.size())
        biggest = n
      end if
    end if
  end for
  if (biggest == emptylist)
    return b
  else
    return biggest
end function


list function caller(list a)
  list b = newlist()
  b.add(12-8)
  a.remove(12-8)
  return sortTupleList(a,b)
end function

此功能将测试从12-8开始的每个模式并比较它们的大小

答案 1 :(得分:2)

根据问题的大小(n图块数量),您可以选择以下任一方法:

1- Bruteforce:您可以使用回溯检查所有可能的磁贴配置,这将导致O(n!)复杂度的算法。

2- Bitmask Dynamic Programming:您可以在位掩码的帮助下使用动态编程来减少搜索空间。这种方法将产生O(2^n * n)的算法。

答案 2 :(得分:2)

我从图论的角度来看这个问题,它提供了一些关于问题的见解,并提供了一些可以用来有效解决问题的启发式方法。

首先,构建一个图形,使得您给出的每个项目都对应于图形的边缘。例如,如果您的输入为:1-2,2-3;你构造一个节点图:1,2,3;和边缘(1,2),(2,3)。

此后,您可以看到您的问题与找到最长的路径相同,即最长路径不包含任何多于一条的路径。不幸的是,已知这个问题是NP难的,正如question中所讨论的那样。所以,我们不希望找到一个多项式算法来解决这个问题。

然而,这个问题实际上与Eularian Path的问题非常相似。但是,在Eularian路径中,您可以遍历所有边缘。它有一个非常简单的解决方案:

  

当且仅当恰好为零时,无向图具有欧拉路径   或两个顶点有奇度,如果它的所有顶点都有   非零度属于单个连通分量。

因此,为了解决您的问题,您可以获取包含您要开始的项目的图表的连接组件。您无法访问此连接组件中未包含的项目。因此,您可以忘记图表的所有剩余边缘。

然后,您只需计算每个节点的度数,并检查该图形是否具有前面定义的欧拉路径。如果有,那你很幸运。因为你不可能拥有比这条路径更长的链。

您可以通过Fleury's Algorithm轻松计算此链。

但是,如果此组件没有Eualirian路径,那么您至少知道不存在此组件边缘大小的链或更多。

Handshaking Lemma告诉我们:

  

每个无向图都有偶数个奇数度的顶点。

如果不存在欧拉路径,那么我们知道我们有 2k 节点具有奇数度,其中 k> 1 。因此,我们需要删除最小数量的边缘,以便我们有 k = 1 。但是,您需要考虑到当删除某些边时,可能无法连接剩余的边。

因此,我想到的最佳启发式方法是找到边缘,使其两个顶点都具有奇数度,并且移除它不会撕裂连接的组件。如果我们可以找到这样的 k - 1 顶点,那么当我们删除它们时,我们将有一个连通的组件,我们将只有2个具有奇数度的顶点。因此,我们可以通过使用Fleury算法找到欧拉路径,轻松找到最长链。

答案 3 :(得分:1)

将数字视为顶点,将对视为图的边(因此可能存在一些多边)。现在你的问题被简化为找到图中最长的路径,其中顶点(但不是边缘)可能会重复。

答案 4 :(得分:1)

保持错误主义的想法,我们可以将图形的状态定义为边数,奇数度的顶点数,顶点的散列及其连接,以及一组具有奇数的边度顶点。如果奇数度顶点的数量等于2,我们可以通过减去min(2, number of vertices with odd degree)的边数或零来确定状态的优先级。

下面是JavaScript实现的尝试,利用堆作为优先级队列。具有奇度顶点的每个边缘被轮流移除,图形被分析并在适用时被分割成任何单独的组件,并且每个组件被推送到优先级队列。循环退出的时间很早,希望能保证以欧拉路径返回的第一个图也具有最长的可实现性。



var Heap = function (f){
  this.heap = [];
  this.isPriority = f || function(a,b){ return a > b; };
}

Heap.prototype.put = function(val){
  this.heap.push(val);

  var i = this.heap.length - 1,
      parent = i - 1 >> 1;

  while (i !== 0 && this.isPriority(this.heap[i],this.heap[parent])){
    this.heap[i] = this.heap[parent];
    this.heap[parent] = val;
    i = parent;
    parent = i - 1 >> 1
  }

  return this.heap;
}

Heap.prototype.get = function(val){
  if (this.heap.length === 0){
    return null;
    
  } else if (this.heap.length === 1){
    return this.heap.pop();
  }

  var first = this.heap[0],
      last = this.heap.pop(),
      i = 0;

  this.heap[i] = last;

  while (true){
    var j = 2*i + 1;

    if (this.heap[j] === undefined){
      break;
    }

    if (this.heap[2*i + 2] !== undefined && this.isPriority(this.heap[2*i + 2],this.heap[j])){
      j = 2*i + 2;
    }

    if (this.isPriority(this.heap[j],this.heap[i])){
      this.heap[i] = this.heap[j];
      this.heap[j] = last;
      i = j;
    } else {
      break;
    }
  }

  return first;
}

function makeGraphs(graph){
  // separate disconnected graphs
  var graphs = [],
      index = 0,
      visited = new Set();
      
  function traverse(v){  
    visited.add(v);
    
    var vs = graph.vertices[v];
    
    if (vs.length > 0){
      graphs[index].vertices[v] = [];
    }
    
    for (var i in vs){
      graphs[index].vertices[v].push(vs[i]);
      graphs[index].numEdges++;
      
      if (!visited.has(vs[i])){
        traverse(vs[i]);
      }
    }
  }
  
  for (var i in graph.vertices){
    if (!visited.has(i) && graph.vertices[i].length >0){
      graphs.push({vertices: {}, numEdges: 0});
      traverse(i);
      index++;
    }
  }
  
  // enumerate odd degree vertices and their edges
  for (var i=0; i<graphs.length; i++){
    graphs[i].numEdges /= 2;
  
    graphs[i].numOddDegreeVertices = 0;
    graphs[i].edgesWithOddDegreeVertices = new Set();
  
    for (var u in graphs[i].vertices){
      if (graphs[i].vertices[u].length & 1){
        graphs[i].numOddDegreeVertices++;
        
        graphs[i].vertices[u].forEach(function(v){
          var edge = u + '-' + v;
          
          if (!graphs[i].edgesWithOddDegreeVertices.has(edge) 
           && !graphs[i].edgesWithOddDegreeVertices.has(v+'-'+u)){
            graphs[i].edgesWithOddDegreeVertices.add(edge);
          }
        });
      }    
    }
  }
  
  return graphs;
}

function potentialEdges(graph){
  if (graph.numOddDegreeVertices === 2){
    return graph.numEdges;
  }
  return graph.numEdges - Math.min(2,graph.numOddDegreeVertices);
}

function removeEdge(graph,edge){
  var vertices = edge.split("-"),
      u = vertices[0],
      v = vertices[1];
      
  graph.vertices[u].splice(graph.vertices[u].indexOf(v),1);
  graph.vertices[v].splice(graph.vertices[v].indexOf(u),1);
  graph.edgesWithOddDegreeVertices.delete(edge);
  
  return graph;
}

function hasEulerianPath(graph){
  if (graph.numOddDegreeVertices === 2 || graph.numOddDegreeVertices === 0){
    return true;  
  }
  return false;
}

function copyGraph(graph){
  var copy = {
    vertices: {},
    numEdges: graph.numEdges,
    numOddDegreeVertices: graph.numOddDegreeVertices,
    edgesWithOddDegreeVertices: new Set(graph.edgesWithOddDegreeVertices)
  };
  
  for (var v in graph.vertices){
    copy.vertices[v] = graph.vertices[v].slice();
  }
  
  return copy;
}

function f(ps){
  var edges = [],
      edgeIndexes = {},
      graph = {vertices: {}};
      
  for (var i=0; i<ps.length; i++){
    edgeIndexes[ps[i]] = i;
    edges[i] = ps[i].split("-");
  }
  
  for (var i=0; i<edges.length; i++){  
    if (graph.vertices[edges[i][0]] !== undefined){
      graph.vertices[edges[i][0]].push(edges[i][1]);
      
    } else {
      graph.vertices[edges[i][0]] = [edges[i][1]];
    }
    
    if (graph.vertices[edges[i][1]] !== undefined){
      graph.vertices[edges[i][1]].push(edges[i][0]);
      
    } else {
      graph.vertices[edges[i][1]] = [edges[i][0]];
    }
  }
  
  var heap = new Heap(function(a,b){
    return potentialEdges(a) > potentialEdges(b);
  });
  
  var graphs = makeGraphs(graph);

  for (var i=0; i<graphs.length; i++){
    heap.put(graphs[i]);
  }
  
  var current = heap.get();

  while (current !== null){
    if (current.numEdges > 1 && hasEulerianPath(current)){
      return current;
    }
    
    current.edgesWithOddDegreeVertices.forEach(function(edge){
      var copy = copyGraph(current);

      removeEdge(copy,edge);
      graphs = makeGraphs(copy);
      
      for (var i=0; i<graphs.length; i++){
        heap.put(graphs[i]);
      }
    });
    
    current = heap.get();
  }
 
  return "The longest chain appears to be one edge only.";
}

var input = ['7-4','11-8','11-11','1-0','4-2','7-5','10-8','7-3','10-5','7-2','9-8','12-8','0-0','11-10'];

console.log('Input: ' + input.join(', '));
console.log('---');
console.log('Output: ' + JSON.stringify(f(input)));
console.log('---');
console.log("OP's example solution: 12-8, 8-11, 11-11, 11-10, 10-5, 5-7, 7-4, 4-2, 2-7, 7-3");
&#13;
&#13;
&#13;