直接穷举吧
In[50]:= t = {{13, 15}, {10, 20}, {20, 16}, {8, 10}};
{#, Fold[{#1[[1]] + #2[[1]],
Max[#1[[1]] + #2[[1]], #1[[2]]] + #2[[2]]} &, {0, 0},
t[[#]]][[2]]} & /@ Permutations[Range@Length[t]] //
MinimalBy[#, Last] &
Out[51]= {{{4, 2, 1, 3}, 69}, {{4, 2, 3, 1}, 69}}
Permutations表示所有可能的排列顺序,对每种排列顺序用Fold算出所需时间,最后用MinimalBy选出用时最短的就行了
Fold里面的具体含义是假设第i个人离开第轮的时刻为${t_{i,1},t_{i,2}}$
如果t中元素的长度不为2,更一般的写法如下
{#, Fold[Block[{i = 2, list = #2},
FoldList[Max[#2, #1 + list[[i++]]] &, #1 + list]] &,
ConstantArray[0, Length@t[[1]]], t[[#]]][[-1]]} & /@
Permutations[Range@Length[t]] // MinimalBy[#, Last] &
中间那个FoldList的作用就是替代嵌套的Max,只要搞清楚#1、#2分别代表什么还是很容易看懂的(注意#1 + list中的#1和#1 + list[[i++]]中的#1不同)
===========================9月10日编辑===================================
在下面瓦屋的答案里提到了用LinearProgramming做0-1规划,所以来补充一下做法
首先需要承认MMA里LinearProgramming的帮助并不是特别的好懂,虽然道理都说得挺明白了然而看着总是有些蛋疼,所以我特意写了下注释,对照帮助应该就能比较清楚了
(t = {{13, 15, 20}, {10, 20, 18}, {20, 16, 10}, {8, 10, 15}};
{n, m} = Dimensions[t];(*n个人,共m轮*)
max = n*Max@Total[t, {2}];(*总时间不超过用时最多的一个人的n倍*)
(*待规划变量,x[i,j]为第i个人开始第j轮的时间,
y[i,k]表示第k个人是不是排在第i个人后面(1为是0为不是),
T为总时间*)
X = Flatten[{Array[x, {n, m}],
Table[y[i, k], {i, 1, n - 1}, {k, i + 1, n}], T}];
cons = Flatten[{
(*每个人只有完成前面的面试才能进入下一阶段的面试*)
Table[
x[i, j + 1] - x[i, j] >= t[[i, j]], {i, 1, n}, {j, 1, m - 1}],
(*每个阶段面试不超过一个人*)
Table[
x[i, j] - x[k, j] + max y[i, k] <= max - t[[i, j]], {i,
n - 1}, {k, i + 1, n}, {j, m}],
Table[
x[i, j] - x[k, j] + max y[i, k] >= t[[k, j]], {i, n - 1}, {k,
i + 1, n}, {j, m}],
(*总时间大于等于每个人完成的时间*)
Table[T - x[i, m] >= t[[i, m]], {i, n}]
}];
ans = LinearProgramming[
(*使得c.X为T*)
ReplacePart[ConstantArray[0, Length@X], -1 -> 1],
(*将约束整理为矩阵形式*)
Function[cond, Coefficient[cond[[1]], #] & /@ X] /@ cons,
{cons[[All, 2]],
cons[[All, 0]] /. {GreaterEqual -> 1, LessEqual -> -1,
Equal -> 0}}\[Transpose],
(*变量取值范围,x[i,j]与T为0到max,y[i,j]为0或1*)
X /. {x[__] :> {0, max}, y[__] :> {0, 1}, T -> {0, max}},
(*求解数域为整数域*)
Integers]) // AbsoluteTiming
(*将结果处理为顺序形式*)
rules = Thread[X -> ans];
{ans[[-1]], Sort[Range[n], (y[##] /. rules) == 1 &]}
结果如下
{0.0109446, {8, 21, 36, 21, 36, 56, 31, 56, 74, 0, 8, 18, 1, 1, 0, 1,
0, 0, 84}}
{84, {4, 1, 2, 3}}
可以看到用时只有0.011s,虽然还是比直接枚举慢一个数量级,然而已经比Minimize高到不知哪里去了
(好吧我仔细试了一下,发现LinearProgramming快主要是因为用了浮点数,把Minimize换成NMinimize速度就基本一样了。。。。。)