CJam,119 91字节
q~:M;),>:R;(:L{{R{ML)d/-Y#)mr}$L/L<2{{M1$:+-+}%z}*:U:+__O|=R*-}gU{:s_:,:e>f{Se[}}%zSf*N*}M?
这是一种可以证明是正确的,不确定的方法。
在我的桌面上,第二个测试用例通常会在不到10分钟的时间内完成。
第一种情况立即完成。在CJam解释器中在线尝试。
样品运行
$ cjam grid.cjam <<< '8 1 300 500'
77 66 37 47 56 46 86 85
63 102 70 72 49 54 81 9
62 69 58 57 71 17 48 118
64 65 67 87 53 44 80 40
73 60 55 89 51 76 84 12
68 59 28 78 74 38 50 105
61 75 52 43 125 83 42 19
32 4 133 27 21 142 29 112
理念
没有时间限制,我们可以随机生成正方形,直到找到有效的正方形。这种方法基于该思想,并添加了两个优化:
代替伪随机生成边长为N的正方形,我们生成边长为N-1的正方形,添加一列以形成N×(N-1)个矩形,其行的总和为S,然后一行形成一个平方的正方形边长ñ其列有总和小号。
由于所有列的元素的总和将是NS和第一的元素之和N-1行是(N-1)s,在最后一行也将有总和小号。
但是,此过程可能会生成无效的矩阵,因为不能保证最后一行和最后一列的所有元素都是唯一的或落在[A ... B]范围内。
随机选择[A ... B]和边长N-1的唯一整数的平方会花费太长时间。在应用上一个项目符号要点中详细介绍的过程之后,我们必须以某种方式优先考虑那些更有可能导致边长为N的有效平方的平方。
假定每个行和列必须具有的总和小号,其元素具有的平均S / N。因此,选择更多接近该平均值的元素将增加我们的机会。
对于每个我在[A ... B] ,我们伪随机挑之间的浮子0和(I - S / N)2 + 1和排序的元素[A ... B]由拾取浮动。我们保留前N 2个数字,并将它们按阅读顺序放在一个正方形中。
假设每一步中0和(I-S / N)2 +1之间的所有实数的分布完全均匀,则所有正方形的被拣选概率都为非零,这意味着该过程将最终完成。
码
q~ e# Read all input from STDIN and evaluate it.
:M; e# Save "S" in M and discard it from the stack.
),>:R; e# Transform "A B" into [A ... B], save in R and discard.
(:L e# Save "N - 1" in L and keep it on the stack.
{ e# If L is non-zero:
{ e# Do:
R{ e# For each I in R:
ML)d/ e# Compute M/Double(L+1).
-Y# e# Subtract the result from I and square the difference.
)mr e# Add 1 and pick a non-negative Double below the result.
}$ e# Sort the values of I according to the picks.
L/ e# Split the shuffled R into chunks of length L.
L< e# Keep only the first L chunks.
2{ e# Do twice:
{ e# For each row of the L x L array.
M1$ e# Push M and a copy of the row.
:+- e# Add the integers of the row and subtract their sum from M.
+ e# Append the difference to the row.
}% e#
z e# Transpose rows and columns.
}* e#
:U:+ e# Save the result in U and concatenate its rows.
__O| e# Push two copies. Deduplicate the second copy.
=R* e# Push R if all elements are unique, an empty array otherwise.
- e# Remove the result's elements from U's elements.
}g e# If the resulting array is non-empty, repeat the loop.
U{ e# For each row in U:
:s e# Convert its integers into strings.
_:, e# Copy and replace each string with its length.
:e> e# Compute the maximum length.
f{ e# For each integer, push the maximum length; then
Se[ e# Left-pad the integer with spaces to that length.
} e#
}% e#
z e# Transpose rows with columns.
Sf*N* e# Join columns by spaces, rows by linefeeds.
}M? e# Else, push M.