这是一个自动回答的问题,源自this more specific question,在选择错误的(恕我直言)答案后,OP似乎已失去兴趣。
我确实检查了之前关于这个问题的问题,但似乎都没有解决这个问题。
想象一下,你有4个人:Abdul,Beatrix,Charlie和Daria 你想存储关于这些人对彼此的感受的信息
Abdul and Beatrix are in love
Beatrix and Charlie hate each other
Abdul and Charlie are good friends
Daria and Beatrix don't know each other
etc.
在简洁而没有诗歌的计算机世界中,这可以转化为:
relation (Abdul , Beatrix) = love;
relation (Beatrix, Charlie) = hate;
relation (Abdul , Charlie) = friendship;
etc.
换句话说,如果您想映射每对人之间的关系,您将需要一个数据结构,允许您为每对人保持唯一值。
尽管有许多方法可以实现合适的数据结构,但在某些情况下,您可能希望此表是一个固定大小的数组,直接由表示给定关系的对索引。
给定I N 前N个自然整数的集合,让我们称之为P N I N的所有无序对(a,b)的序列使得<> b,按字典顺序排序。
在(希望)不那么神秘的英语中, P列举了我 的两个元素之间的所有可能关系。
示例(对于N = 4):
我 4 =(0,1,2,3)
P 4 =((0,1),(0,2),(0,3),(1,2),(1,3),(2,3))
请注意,P N 的基数为N(N-1)/ 2,因此
P N 中最紧凑的零基指数将在[0..N(N-1)/ 2-1]范围内。
如何以紧凑有效的方式索引P N ?
在其他方面,
排列P N 的方式不太重要,但是词典顺序可能是最方便的。
示例:
P 4 =((0,1),(0,2),(0,3),(1,2),(1,3),(2, 3))
p 4 (1,3)= 4
p 4 -1 (4)=(1,3)
答案 0 :(得分:2)
这似乎更像是一个数学问题。
如果我的计算是正确的,那么,
For a pair P (a,b), the number of pairs of type (a,x) [x < b] before P shall be b-a-1.
The number of pairs of type (x,y) [x < a] = (n-1)+(n-2)+(n-3)...+(n-a) = a*n - a(a+1)/2
Hence total number of pairs before P = (b-a-1) + a*n - a(a+1)/2.
因此指数P =(b-a-1)+ a * n - a(a + 1)/ 2。
对于反向索引,首先找到a,因为我们知道对于第一个n-1项,a = 0,对于下一个n-2项,a = 1,等等。
这可以在O(N)时间内迭代这些值并查看它何时超过索引。
一旦找到a,就可以从上面的等式中找到b。
答案 1 :(得分:2)
到目前为止我在这里看到的两个答案都是第一次计算正常,但是反向计算需要循环,这是不必要的。
使用n=5
考虑以下示例,显示元素的编号方式。
0 1 2 3 4
+---+---+---+---+---+
0 | | | | | |
+---+---+---+---+---+
1 | 0 | | | | |
+---+---+---+---+---+
2 | 1 | 4 | | | |
+---+---+---+---+---+
3 | 2 | 5 | 7 | | |
+---+---+---+---+---+
4 | 3 | 6 | 8 | 9 | |
+---+---+---+---+---+
给定元组(x, y)
(假设x < y
),列x
中的第一个索引由
n-1 + n-2 + ... + n-x = (n-1 + n-x) * x / 2 = (2n - x - 1) * x / 2
该列中的偏移量只是y - x - 1
。这产生了总表达式
p_n(x, y) = (2n - x - 1) * x / 2 + y-x-1 = (2n - x - 3) * x / 2 + y-1
现在,走另一条路是很棘手的。我们有一些值p
和n
,需要找到x
和y
。通过假设我们正在寻找列中的第一个单元格,即y = x+1
,我们可以使我们的生活更简单。如果我们在上面的公式中插入它,我们获得
p = (2n - x - 1) * x / 2
重写此公式会产生
x^2 - (2n-1) * x + 2p = 0
这是一个简单的二次方程,可以求解x:
x = [(2n-1) - Sqrt((2n-1)^2 - 8p)] / 2
当然,我们可能会高估x
,因为我们假设y
的值尽可能低。但是,我们并没有那么遥远(仍在右栏中),因此对该值进行四舍五入足以得到真实的x
。
将我们找到的x
值插入到原始公式中会为y
生成一个非常简单的等式:
x = Floor( [(2n-1) - Sqrt((2n-1)^2 - 8p)] / 2 )
y = p - (2n - x - 3) * x / 2 + 1
可以说,取一个数的平方根是一个缓慢的操作(这是正确的),但这种方法将胜过更大值n
的循环。
答案 2 :(得分:0)
让a和b为I N 的两个元素,其中&lt; B'/强>
如果我们将P表示为半填充矩阵,那么我们的想法是在每行的开头添加一个偏移量,以便在下一行的开头获得连续的数字。
第0行以0的偏移量开始,包含N-1个值
第1行从N-1开始并包含N-2值
等。
行a
的偏移值将是(1..a)中i的N-i
的总和。
最终对索引将为offset(a)+b
。
偏移量(a)的计算是通过使用给出前n个整数之和的公式来完成的:s(n)= n(n-1)/ 2.
这里offset(a)将是= s(N)-s(a)。
经过一些数学运算后,得到的公式可以写成:
p N (a,b)= a(2N-a-3)/ 2 + b - 1
P的伪代码是:
function p (a,b)
{
if (a>b) swap(a,b)
return a * (2 * N - a - 3) / 2 + b - 1
}
所有功劳都归功于Heuster寻找问题的优雅解决方案 有关详细信息,请参阅所选答案。
这是伪代码:
const N1 = 2 * N - 1
const N2 = N1 * N1
function reverse_p (p)
{
a = floor( (N1 - sqrt(N2 - 8 * p)) / 2)
b = p - (2 * N - a - 3) * a / 2 + 1
return (a, b)
}