我有n个顶点编号为1 ... n,并希望将每个顶点与所有其他顶点配对。这将导致n *(n-1)/ 2个边数。每个顶点都有一定的强度。两个顶点的强度之差是边缘的权重。我需要得到总重量。使用两个循环我可以在O(n ^ 2)时间内完成此操作。但我想减少时间。我可以使用邻接列表并使用它创建n *(n-1)/ 2边的图形但是如何在不使用两个循环的情况下创建邻接列表。输入只接受顶点的数量和每个顶点的强度。
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
int w=abs((strength[i]-strength[j]));
sum+=w;
}
这就是我之前所做的。我需要一种更好的方法来做到这一点。
答案 0 :(得分:3)
如果有O(N*N)
个边缘,则无法在线性时间内全部列出。
但是,如果您确实只需要计算总和,那么这是O(N*log(N))
中的解决方案。您可以使用O(N)
排序算法来改进解决方案,例如radix sort。
#include <algorithm>
#include <cstdint>
// ...
std::sort(strength, strength+n);
uint64_t sum = 0;
int64_t runSum = strength[0];
for(int i=1; i<n; i++) {
sum += int64_t(i)*strength[i] - runSum;
runSum += strength[i];
}
// Now "sum" contains the sum of weigths over all edges
解释算法:
这个想法是避免明确地对所有边进行求和(需要O(N*N)
),而是一次添加几个权重的总和。考虑最后一个顶点n-1
和平均A[n-1] = (strength[0] + strength[1] + ... + strength[n-2])/(n-1)
:如果权重都大于(strength[n-1] - A[n-1]) * (n-1)
,我们显然可以一次添加n-1
,即strength[n-1]
个权重,或者比它都小。但是,由于abs
操作,我们必须根据另一个顶点的强度是大于还是小于当前顶点的强度来添加不同的金额。因此,一种解决方案是首先对强度进行排序,以确保每个下一个强度都大于或等于之前的强度。