Arrange pairs of numbers so that members of adjacent pairs are equal

前端 未结 5 1119
北海茫月
北海茫月 2021-01-01 17:38

I would like to arrange the following items, forming the longest chain possible starting with 12-8 and matching the numbers end to end.

My items are 7-4, 11-8, 11-11

相关标签:
5条回答
  • 2021-01-01 18:13

    Depending on the size of your problem ( n number of the tiles ) you can choose either of the following methods:

    1- Bruteforce: You can check all the possible configurations of tiles using backtrack that would result in an algorithm of O(n!) complexity.

    2- Bitmask Dynamic Programming: You can use dynamic programming with the help of bitmask to reduce your search space. This approach will result in algorithm of O(2^n * n).

    0 讨论(0)
  • 2021-01-01 18:13

    Keeping with errorist's idea, we can define a state for a graph as the number of edges, the number of vertices with odd degrees, a hash of vertices and their connections, and a set of edges with an odd degree vertex. We can prioritize the states by the number of edges subtracted by min(2, number of vertices with odd degree) or by zero if the number of odd degree vertices equals 2.

    Below is an attempt at a JavaScript implementation, utilizing a heap for a priority queue. Each edge with an odd degree vertex is removed by turn, the graph is analyzed and split into any separate components when applicable, and each component is pushed to the priority queue. The loop exits early, hopefully guaranteeing that the first graph returned with an Eulerian path also has the longest such achievable.

    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");

    0 讨论(0)
  • 2021-01-01 18:21

    you need recursion, but it might not work on a bigger data set: something like this.

    DISCLAIMER: This is probably not the most optimized solution (complexity O(N!)) but it is very simple to implement if you are allowed to use recursion

    (this is not objective-c code, it's an algorithm, translate it yourself, sorry i don't know objective-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
    

    This function will test every single pattern starting from 12-8 and compare their size

    0 讨论(0)
  • 2021-01-01 18:25

    Think of the numbers as vertices and the pairs as edges of a graph (so there may be some multi-edges). Now your problem is reduced to finding the longest path in the graph where vertices (but not edges) may be repeated.

    0 讨论(0)
  • 2021-01-01 18:31

    I've looked at the problem in a graph-theoretic perspective, which gives some insights about the problem, and provides some heuristics that may be used to solve the problem efficiently.

    First, construct a graph such that every item you are given corresponds to an edge of the graph. For example, if your input given as: 1-2, 2-3; you construct a graph with nodes: 1, 2, 3; and edges (1, 2), (2, 3).

    Thereafter, you can see that your problem is identical to finding the longest trail, i.e., the longest path that does not contain any edge more than one. Unfortunately, this problem is known to be NP-hard, as discussed in this question. So, we cannot hope to find a polynomial algorithm to solve this problem.

    However, this problem is actually very similar to the problem of Eularian Path. However, in an Eularian path you traverse all edges. And it has a very simple solution:

    An undirected graph has an Eulerian path if and only if exactly zero or two vertices have odd degree, and if all of its vertices with nonzero degree belong to a single connected component.

    So in order to solve your problem, you take the connected component of the graph that contains the item you want to start with. You cannot possibly reach the items that are not in this connected component. Therefore, you can forget about all of the remaining edges of the graph.

    Then, you simply count the degrees of each node, and check if that graph has an Eulerian path by the preceding definition. If it has, then you're lucky. Because you can't possibly have a chain longer than this path.

    And you can compute this chain easily by Fleury's Algorithm.

    However, if this component does not have an Eualirian path, then you at least know that there does not exist a chain of the size of the edges of this component or more.

    Handshaking Lemma tells us:

    Every undirected graph has an even number of vertices with odd degree.

    If there does not exists an Eulerian path, then we know that we have 2k nodes with odd degrees where k > 1. So we need to remove minimum number of edges edges so that we have k = 1. However, you need to take into account that when you remove some of the edges, remaining edges may not be connected.

    So the best heuristic that comes to my mind is to find edges such that both of its vertices have odd degrees, and removing it doesn't tear the connected component apart. If we can find such k - 1 vertices, then when we remove them we will stil have a connected component and we will have only 2 vertices with odd degrees. Therefore we can find the longest chain easily, again by finding an Eulerian path using Fleury's algorithm.

    0 讨论(0)
提交回复
热议问题