Algorithm 在一组项目之间建立排序的算法
我有一组学生(为了一般性,在标题中称为项目)。在这些学生中,有些人以任性著称。我们被告知有一系列“我恨j”形式的仇恨关系“我恨j”并不意味着“j恨我”。我们应该把学生排成几行(最前面的一行编号为1),这样如果“我讨厌j”,那么我应该排成一行,严格地说,比j排的少(换句话说,在j排前面的某一行),这样我就不会向j扔东西(不允许向后翻)。找到所需最少行数(每行不需要相同数量的学生)的有效算法是什么 我们将作出以下假设: 1) 如果我们将其建模为有向图,那么图中就没有循环。最基本的循环是:如果“我恨j”是真的,“j恨i”是假的。因为否则,我想订购就不可能了 2) 小组中的每个学生至少被另一个学生憎恨,或者至少憎恨另一个学生。当然,也会有一些学生既被某些人憎恨,又反过来憎恨其他学生。这意味着没有不构成图表一部分的流浪学生 更新:我已经考虑过用I-->j构建一个有向图,如果‘我讨厌j’并进行拓扑排序。然而,因为如果我必须将所有学生排在一行中,一般拓扑排序会更适合。因为这里的行有变化,所以我试图弄清楚如何将变化因素考虑到拓扑排序中,这样它就给出了我想要的 回答时,请说明解决方案的复杂性。如果有人在编写代码,而您不介意使用哪种语言,那么我更喜欢Java,但当然,任何其他语言都可以Algorithm 在一组项目之间建立排序的算法,algorithm,sorting,graph-theory,Algorithm,Sorting,Graph Theory,我有一组学生(为了一般性,在标题中称为项目)。在这些学生中,有些人以任性著称。我们被告知有一系列“我恨j”形式的仇恨关系“我恨j”并不意味着“j恨我”。我们应该把学生排成几行(最前面的一行编号为1),这样如果“我讨厌j”,那么我应该排成一行,严格地说,比j排的少(换句话说,在j排前面的某一行),这样我就不会向j扔东西(不允许向后翻)。找到所需最少行数(每行不需要相同数量的学生)的有效算法是什么 我们将作出以下假设: 1) 如果我们将其建模为有向图,那么图中就没有循环。最基本的循环是:如果“我恨j
JFYI这不是针对任何类型的家庭作业(顺便说一句,我不是学生。)。我觉得你需要调查。基本上,假设1中的重要一点是,这张图中不能有任何循环。如果存在任何循环,则无法解决此问题 首先,我会让所有不讨厌其他学生的学生坐在后排。然后你可以让讨厌这些学生的学生坐在下一排,以此类推。简单答案=1排 把所有学生放在同一排 实际上,这可能无法解决所述的问题-较小的行,而不是相等的行
但我确信有更好的算法——看看非循环图。这个问题基本上是解决这个问题的另一种方法。行数实际上是路径中的节点数(边数+1) 假设图为,则解决方案为。 你的假设1的非循环性更强一些。不仅A->B和B->A无效。还有A->B,B->C,C->A和任何长度的任何循环
提示:问题是需要多少行,而不是哪一个学生在哪一行。这个问题的答案是最长路径的长度。它来自项目管理理论(或进度安排理论,我不知道确切的术语)。这里的任务是排序作业(顶点是作业,弧是作业顺序关系) 显然,我们有一些无环的连通定向图。从顶点
a
到顶点b
有一条弧,当且仅当a
讨厌b
。让我们假设有一个源(没有传入弧)和目标(没有传出弧)顶点。如果不是这样的话,就加上假想的。现在我们想要找到从源到目标的最长路径的长度(它将是行数-1,但请注意假想的顶点)
我们将顶点秩(r[v]
)定义为源和该顶点之间最长路径中的弧数v
。显然,我们想知道r[目的地]
。求秩的算法:
0) r_0[v] := 0 for all verteces v
repeat
t) r_t[end(j)] := max( r_{t-1}[end(j)], r_{t-1}[start(j)] + 1 ) for all arcs j
until for all arcs j r_{t+1}[end(j)] = r_t[end(j)] // i.e. no changes on this iteration
在每一步上,至少有一个顶点增加其秩。因此,在这种形式下,复杂性是O(n^3)
顺便说一下,这个算法还提供了学生在行中的分布。把学生按他们各自的级别分组
编辑:另一个具有相同想法的代码。也许这更容易理解
# Python
# V is a list of vertex indices, let it be something like V = range(N)
# source has index 0, destination has index N-1
# E is a list of edges, i.e. tuples of the form (start vertex, end vertex)
R = [0] * len(V)
do:
changes = False
for e in E:
if R[e[1]] < R[e[0]] + 1:
changes = True
R[e[1]] = R[e[0]] + 1
while changes
# The answer is derived from value of R[N-1]
#Python
#V是顶点索引的列表,让它类似于V=range(N)
#源具有索引0,目标具有索引N-1
#E是边的列表,即形式的元组(起始顶点、结束顶点)
R=[0]*len(V)
做:
更改=错误
对于e中的e:
如果R[e[1]]
当然,这是最简单的实现。它可以被优化,并且时间估计可以更好
Edit2:明显优化-仅更新与上一步更新的顶点相邻的顶点。也就是说,引入一个队列,队列中的顶点已更新。对于边存储,也应使用邻接列表。有了这样的优化,复杂性将是O(N^2)。实际上,每个顶点最多可以出现在队列中
rank
次。但顶点秩永远不会超过顶点数。因此,算法步骤的总数不会超过O(N^2)行数是有向图中最长路径的长度加上一。作为一种极限情况,如果没有仇恨关系,每个人都可以坐在同一排
要分配行,请将所有不被
S = set of students
for s in S: s.row = -1 # initialize row field
rownum = 0 # start from first row below
flag = true # when to finish
while (flag):
rownum = rownum + 1 # proceed to next row
flag = false
for s in S:
if (s.row != -1) continue # already allocated
ok = true
foreach q in S:
# Check if there is student q who will sit
# on this or later row who hates s
if ((q.row == -1 or q.row = rownum)
and s hated by q) ok = false; break
if (ok): # can put s here
s.row = rownum
flag = true
postNodeCb( graph g, int node )
{
if ( /* No adj list */ )
row[ node ] = 0;
else
row[ node ] = max( row number of all children ) + 1;
}
main()
{
.
.
for ( int i = 0; i < NUM_VER; i++ )
if ( !visited[ i ] )
graphTraverseDfs( g, i );`enter code here`
.
.
}