The aim of this puzzle is to match a scatterplot with one of a few complexity functions. As these functions have a x↦xαβxlogx form, one of the most complete solution would be to use the method of least squares. But for this puzzle, you can settle for a lighter method, for example computing the scatterplots corresponding to the complexity functions, and find a formula to assess their likelihood to the original scatterplot.
Note that the Θ(n3) validation test can be tricky to pass with this method, as the data set is a Θ(n2.8) which is closer to a Θ(n2logn) on the interval studied. A hack around this is to add the Θ(n2.5) complexity function, and output Θ(n3) when it is recognized.
- import math
- # name, and function of the main complexities
- names = ["1","log n","n","n log n", "n^2", "n^2 log n", "n^3", "2^n"]
- complexities = [lambda x: 1,
- lambda x: math.log(x),
- lambda x: x,
- lambda x: x*math.log(x),
- lambda x: x**2,
- lambda x: x**2*math.log(x),
- lambda x: x**3,
- lambda x: math.pow(2,x)]
- # maximum value which can be fed to the corresponding complexity function
- # without overflow
- upperLimit = [None, None, None, None, None, None, None, 500]
- # Read input, storing data volumes in x, and execution times in perf
- x, perf = [], []
- for i in range(int(input())):
- a, b = [int(j) for j in input().split()]
- x.append(a)
- perf.append(b)
- # for each complexity function f, computes a normalized variance of the ratio (perf/f)
- # It it is not representative (variance over less than 5 values) stores -1 instead
- # Then updates minVariance and result so that minVariance stays the minimal
- # representative variance found yet, and result is the number of the corresponding
- # function, which is the most probable complexity function found yet
- variances, minVariance, result = [], sys.maxsize, -1
- for i in range(len(complexities)):
- f = complexities[i]
- # takes upperLimit into account to avoid an overflow
- maxDataVolume = len(x)
- if upperLimit[i] != None:
- for j in range(len(x)):
- if x[j] > upperLimit[i]:
- maxDataVolume = j-1
- break
- ratio = [ perf[j]/f(x[j]) for j in range(maxDataVolume)]
- if (len(ratio) < 5):
- variances.append(-1)
- else:
- mean = sum(ratio) / len(ratio)
- variances.append(sum([(val-mean)**2 for val in ratio]) / mean**2)
- if (variances[-1] < minVariance):
- minVariance = variances[-1]
- result = i
- print("O({})".format(names[result]))