我想安排以下项目,从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
如何为此任务编写正确的排序算法?
答案 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;