सभी सबसेट के उत्पाद लेने के लिए सबसे तेज़ एल्गोरिथम


23

nकिसी सरणी में संख्याओं को देखते हुए (आप मान नहीं सकते कि वे पूर्णांक हैं), मैं आकार के सभी सबसेट के उत्पाद की गणना करना चाहूंगा n-1

आप इसे सभी संख्याओं को एक साथ गुणा करके और फिर प्रत्येक में बारी-बारी से विभाजित करके कर सकते हैं, जब तक कि कोई भी संख्या शून्य न हो। हालांकि, कितनी जल्दी आप इसे बिना किसी विभाजन के कर सकते हैं?

यदि आप विभाजन की अनुमति नहीं देते हैं, तो आकार n-1 के सभी सबसेट के उत्पाद की गणना करने के लिए अंकगणितीय संचालन (जैसे गुणा और जोड़) की न्यूनतम संख्या क्या है?

स्पष्ट रूप से आप इसे (n-1)*nगुणा में कर सकते हैं ।

स्पष्ट करने के लिए, आउटपुट nअलग-अलग उत्पाद हैं और केवल पढ़ने और लिखने से लेकर मेमोरी की अनुमति के अलावा संचालन गुणा, जोड़ और घटाव हैं।

उदाहरण

यदि इनपुट में तीन नंबर हैं 2,3,5, तो आउटपुट तीन नंबर है 15 = 3*5, 10 = 2*5और 6 = 2*3

कसौटी जीतना

उत्तर अंकगणितीय परिचालनों की संख्या के लिए एक सटीक सूत्र देना चाहिए जो उनके कोड का उपयोग करेगा n। जीवन को सरल बनाने के लिए, मैं n = 1000इसके स्कोर को आंकने के लिए आपके फार्मूले में प्लग करूँगा । कम बेहतर है।

यदि आपके कोड के लिए एक सटीक सूत्र का उत्पादन करना बहुत कठिन है, तो आप इसे n = 1000कोड में अंकगणित संचालन के लिए बस चला सकते हैं । एक सटीक सूत्र हालांकि सबसे अच्छा होगा।

n=1000आसान तुलना के लिए आपको अपने उत्तर के लिए अपना अंक जोड़ना चाहिए ।


4
क्या हम मुफ्त के रूप में 1 से गुणा कर सकते हैं? अन्यथा मैं एक कस्टम-गुणन फ़ंक्शन को परिभाषित करता हूं जो ऐसा करता है।
xnor

3
क्या यह पर्याप्त संख्या में स्पेसर 0 के साथ एक साथ संख्याओं को समांतर करके गुणा के पूरे समूह को करने के नियमों के विरुद्ध होगा?
xnor

1
क्या ऑपरेशंस जैसे सूचकांक+ पर भरोसा करते हैं? यदि यह मामला है, तो क्या सरणी अनुक्रमण गिनती भी है? (चूंकि इसके अलावा और डेरेफेरिंग के लिए सभी सिंटैक्टिक चीनी के बाद है)।
नूर

2
@ नॉर ओके मैं देता हूं :) बस अंकगणित संचालन को गिनें, जिसमें किसी तरह से इनपुट शामिल हो।
आर्थर

1
जाहिर है आप में कर सकते हैं (n-1)*nगुणा तुम्हारा मतलब है (n-2)*n, है ना?
लुइस मेंडो

जवाबों:


25

पायथन, 3 (एन -2) संचालन, स्कोर = 2994

l = list(map(float, input().split()))
n = len(l)

left = [0] * len(l)
right = [0] * len(l)
left[0] = l[0]
right[-1] = l[-1]
for i in range(1,len(l)-1):
  left[i] = l[i] * left[i - 1]
  right[-i-1] = l[-i-1] * right[-i]

result = [0] * len(l)
result[-1] = left[-2]
result[0] = right[1]
for i in range(1, len(l) - 1):
  result[i] = left[i - 1] * right[i+1]

print(result)

सरणियों leftऔर rightक्रमश: बाएं से और सही से सरणी के संचयी उत्पादों होते हैं।

संपादित करें: प्रमाण कि 3 (n-2) n> = 2 के लिए आवश्यक संचालन की इष्टतम संख्या है, यदि हम केवल गुणा का उपयोग करते हैं।

हम इसे प्रेरण द्वारा करेंगे; उपरोक्त एल्गोरिथ्म द्वारा, हमें सिर्फ यह साबित करना है कि n> = 2, 3 (n-2) के लिए आवश्यक गुणा की संख्या पर एक कम बाध्य है।

N = 2 के लिए, हमें कम से कम 0 = 3 (2-2) गुणा चाहिए, इसलिए परिणाम तुच्छ है।

N> 2, और n - 1 तत्वों के लिए मान लें, हमें कम से कम 3 (n-3) गुणा की आवश्यकता है। कश्मीर तत्वों के साथ n तत्वों के लिए एक समाधान पर विचार करें। अब, हम इन तत्वों में से अंतिम को हटा देते हैं जैसे कि यह 1 था, और इसके द्वारा सीधे सभी गुणन को सरल बनाते हैं। हम अन्य सभी तत्वों के उत्पाद के लिए अग्रणी गुणन को भी हटा देते हैं, क्योंकि एक की आवश्यकता नहीं है क्योंकि इसे अन्य तत्वों के n-2 के उत्पाद को प्राप्त करने के लिए मध्यवर्ती मूल्य के रूप में कभी भी उपयोग नहीं किया जा सकता है, क्योंकि विभाजन की अनुमति नहीं है। यह हमें एल गुणा, और n - 1 तत्वों के लिए एक समाधान के साथ छोड़ देता है।

प्रेरण परिकल्पना द्वारा, हमारे पास l> = 3 (n-3) है।

अब, चलो देखते हैं कि कितने गुणा हटा दिए गए थे। उनमें से एक आखिरी को छोड़कर सभी तत्वों के उत्पाद के लिए अग्रणी था। इसके अलावा, अंतिम तत्व का उपयोग कम से कम दो गुणा में सीधे किया गया था: यदि इसका उपयोग केवल एक में किया गया था, तो इसका उपयोग तब किया गया था जब एक मध्यवर्ती परिणाम से गुणा करके अन्य तत्वों के कुछ उत्पाद शामिल थे; मान लीजिए, सामान्यता की हानि के बिना, इस मध्यवर्ती परिणाम में उत्पाद में पहला तत्व शामिल था। फिर, सभी तत्वों के उत्पाद को प्राप्त करने का कोई तरीका नहीं है, लेकिन पहला, क्योंकि प्रत्येक उत्पाद में अंतिम तत्व होता है या तो अंतिम तत्व होता है, या पहला तत्व होता है।

इस प्रकार हमारे पास k> = l + 3> = 3 (n-2) है, जो प्रमेय का दावा करता है।


8
यह पता चला है हास्केल में बहुत साफ : f l = zipWith (*) (scanl (*) 1 l) (scanr (*) 1 $ tail l)
xnor

टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
डेनिस

12

हास्केल , स्कोर 2994

group :: Num a => [a] -> [[a]]
group (a:b:t) = [a,b] : group t
group [a] = [[a]]
group [] = []

(%) :: (Num a, Eq a) => a -> a -> a
a % 1 = a
1 % b = b
a % b = a * b

prod_one_or_two :: (Num a, Eq a) => [a] -> a
prod_one_or_two [a, b] = a % b
prod_one_or_two [x] = x

insert_new_value :: (Num a, Eq a) => ([a], a) -> [a]
insert_new_value ([a, b], c) = [c % b, c % a]
insert_new_value ([x], c) = [c]

products_but_one :: (Num a, Eq a) => [a] -> [a]
products_but_one [a] = [1]
products_but_one l = 
    do combination <- combinations ; insert_new_value combination
    where 
        pairs = group l
        subresults = products_but_one $ map prod_one_or_two pairs
        combinations = zip pairs subresults

इसे ऑनलाइन आज़माएं!

कहते हैं कि हमें सूची दी गई है [a,b,c,d,e,f,g,h]। हम इसे पहले जोड़े में बांटते हैं [[a,b],[c,d],[e,f],[g,h]]। फिर, हम pairsप्राप्त करने के लिए उनके उत्पादों की आधे आकार की सूची पर फिर से उठते हैंsubresults

[a*b, c*d, e*f, g*h] -> [(c*d)*(e*f)*(g*h), (a*b)*(e*f)*(g*h), (a*b)*(c*d)*(g*h), (a*b)*(c*d)*(e*f)]

हम पहले तत्व लेते हैं (c*d)*(e*f)*(g*h), और गुणा यह द्वारा bऔर aक्रमशः, हम सब लेकिन के उत्पाद मिल aऔर सभी लेकिन b। प्रत्येक जोड़ी के लिए ऐसा करना और उस जोड़ी के साथ पुनरावर्ती परिणाम गायब होना, हम अंतिम परिणाम निकालते हैं। विषम-लंबाई के मामले को विशेष रूप से संभाला जाता है क्योंकि विषम तत्व को पुनरावर्ती चरण में अप्रकाशित कर दिया गया है, और शेष तत्वों का उत्पाद बिना इसके उत्पाद है।

गुणा की संख्या t(n)है n/2, जोड़ी उत्पाद के लिए t(n/2)पुनरावर्ती कॉल के लिए, और एक अन्य nअलग-अलग तत्वों के साथ उत्पादों के लिए। यह t(n) = 1.5 * n + t(n/2)विषम के लिए देता है n। आधार मामले के लिए विषम के nसाथ गुणा और अनदेखी के लिए अधिक सटीक गिनती का उपयोग करना 1स्कोर देता 2997है n=1000


यह बहुत अच्छा है।
आर्थर

मुझे लगता है कि स्कोर 2995 है, न कि 2994 जैसा कि मेरे जवाब में यह है कि यह दो नंबरों की गैर-शक्ति में सभी नंबरों के उत्पाद की गणना करता है, जिसे बाद में काट दिया गया। हो products_but_one'सकता है कि सही लंबाई में से कुछ वापस करने से बचने में सावधानी बरती जाए ।
नट

@ मैंने पाया कि मुझे अपनी गिनती में एक अतिरिक्त गुणा करना पड़ा क्योंकि मैं भूल गया कि आधार मामला एक 1ऐसा है जो गुणा करने के लिए स्वतंत्र है। मुझे लगता है कि पैडिंग 1 ने चीजों को प्रभावित नहीं किया, लेकिन मैंने उनका उपयोग न करने के लिए अपने एल्गोरिथ्म को साफ किया।
xnor

क्या यह कोड मानता है कि इनपुट पूर्णांक है?

@ लेम्बिक यह करता है, लेकिन केवल वैकल्पिक प्रकार के एनोटेशन में। मैं उन सभी को बदल दूंगा float
xnor

9

हास्केल , स्कोर 9974

partition :: [Float] -> ([Float], [Float])
partition = foldr (\a (l1,l2) -> (l2, a:l1)) ([],[])

(%) :: Float -> Float -> Float
a % 1 = a
1 % b = b
a % b = a*b

merge :: (Float, [Float]) -> (Float, [Float]) -> (Float, [Float])
merge (p1,r1) (p2, r2) = (p1%p2, map(%p1)r2 ++ map(%p2)r1)

missing_products' :: [Float] -> (Float, [Float])
missing_products' [a] = (a,[1])
missing_products' l = merge res1 res2
    where
        (l1, l2) = partition l
        res1 = missing_products' l1
        res2 = missing_products' l2

missing_products :: [Float] -> [Float]
missing_products = snd . missing_products'

इसे ऑनलाइन आज़माएं!

एक विभाजित और जीत की रणनीति, मर्ज प्रकार की बहुत याद ताजा करती है। कोई अनुक्रमण नहीं करता है।

फ़ंक्शन partitionविभाजन के विपरीत पक्षों पर वैकल्पिक तत्वों को डालकर सूची को समान-समान-संभव-संभव हिस्सों में विभाजित करता है। हम उत्पादों के साथ-एक-लापता और समग्र उत्पाद की सूची के (p,r)साथ परिणाम में से प्रत्येक के लिए परिणाम को मर्ज करते हैं ।rp

पूरी सूची के लिए आउटपुट के लिए, लापता तत्व आधा में से एक में होना चाहिए। उस तत्व को गायब करने वाला उत्पाद आधे के लिए एक-लापता-उत्पाद है, जो दूसरे उत्पाद के लिए पूरे आधे से गुणा करता है। इसलिए, हम प्रत्येक उत्पाद के साथ एक-एक-लापता को दूसरे छमाही के पूर्ण उत्पाद से गुणा करते हैं और परिणामों की सूची बनाते हैं map(*p1)r2 ++ map(*p2)r1)। यह nगुणा लेता है, जहां nलंबाई है। हमें p1*p2भविष्य के उपयोग के लिए एक नया पूर्ण उत्पाद बनाने की भी आवश्यकता है , जिसकी लागत 1 गुना अधिक है।

इस आपरेशन की संख्या के लिए के लिए सामान्य प्रत्यावर्तन देता है t(n)के साथ nभी: t(n) = n + 1 + 2 * t(n/2)। विषम एक समान है, लेकिन उपविदों में से एक 1बड़ा है। पुनरावृत्ति को करते हुए, हम n*(log_2(n) + 1)गुणा प्राप्त करते हैं , हालांकि विषम / समान अंतर उस सटीक मूल्य को प्रभावित करता है। मानों में t(3)से गुणा नहीं द्वारा सुधार कर रहे हैं 1एक प्रकार परिभाषित करते हुए (%)की (*)है कि शॉर्टकट _*1या 1*_मामलों।

यह के 9975लिए गुणा देता है n=1000। मेरा मानना ​​है कि हास्केल के आलस्य का मतलब बाहरी परत में अप्रयुक्त समग्र उत्पाद के लिए गणना नहीं है 9974; अगर मुझसे गलती हुई है, तो मैं इसे स्पष्ट रूप से छोड़ सकता हूं।


आपने मुझे एक मिनट पहले टाइमस्टैम्प से हराया।
गोरे

यदि फॉर्मूला को ठीक से पूरा करना कठिन है, तो बेझिझक इसे केवल इसके लिए चलाएं n = 1000और कोड में अंकगणितीय संचालन की गणना करें।
आर्थर

चूंकि हमारे कोड मूल रूप से एक ही है, मुझे समझ नहीं आता कि कैसे आप को मिल गया है 9974नहीं और 9975के लिए गुणा n = 1000(बाहरी परत में समग्र उत्पाद कंप्यूटिंग के मामले में)। क्या आपने 1इसे परीक्षण करने के लिए उपयोग किए गए इनपुट में शामिल किया था?
nore

@ नोर यू आर राइट, मैं एक के बाद एक। मैंने गुणन फ़ंक्शन कॉल की संख्या के लिए पुनरावृत्ति करने के लिए कोड लिखा था। सीधे कॉल की गिनती अधिक विश्वसनीय होगी - क्या किसी को पता है कि मैं हास्केल में कैसे करूँगा?
xnor

1
@xnor आप उपयोग कर सकते हैं traceसे Debug.Traceएक कैच-ऑल साथ | trace "call!" False = undefinedगार्ड, मुझे लगता है। लेकिन यह unsafePerformIOहुड के तहत उपयोग करता है , इसलिए यह वास्तव में इतना सुधार नहीं है।
सोहम चौधरी

6

हास्केल , स्कोर 2994

group :: [a] -> Either [(a, a)] (a, [(a, a)])
group [] = Left []
group (a : l) = case group l of
  Left pairs -> Right (a, pairs)
  Right (b, pairs) -> Left ((a, b) : pairs)

products_but_one :: Num a => [a] -> [a]
products_but_one [_] = [1]
products_but_one [a, b] = [b, a]
products_but_one l = case group l of
  Left pairs ->
    let subresults =
          products_but_one [a * b | (a, b) <- pairs]
    in do ((a, b), c) <- zip pairs subresults; [c * b, c * a]
  Right (extra, pairs) ->
    let subresult : subresults =
          products_but_one (extra : [a * b | (a, b) <- pairs])
    in subresult : do ((a, b), c) <- zip pairs subresults; [c * b, c * a]

इसे ऑनलाइन आज़माएं!

यह काम किस प्रकार करता है

यह xnor के एल्गोरिथ्म का एक साफ- सुथरा संस्करण है जो विषम मामले को अधिक सीधे तरीके से संपादित करता है (संपादित करें: ऐसा लगता है कि xnor ने इसे उसी तरह से साफ किया है):

[ए, बी, सी, डी, ई, एफ, जी] a
[ए, बीसी, डी, एफजी] c
[(बीसी) (डी) (एफजी), ए (डी) (एफजी), ए (बीसी)] एफजी), (बीसी) (डी)] रिकर्सन द्वारा
([(बीसी) (डी) (एफजी), ए (डी) (एफजी) सी, ए (डी) (एफजी) बी, एक (बीसी) (एफजी) ई, (बीसी) (एफजी) डी, ए (बीसी) (डी) जी, ए (बीसी) (डी)]]

[ए, बी, सी, डी, ई, एफ, जी, एच] c
[एब, सीडी, एफएफ, जीएच] h
[(सीडी) (एफई) (जीएच), (एबी) (एफई) (जीएच), ( ab) (cd) (gh), (ab) (cd) (ef)] recursion d
[(cd) (ef) (gh) b, (cd) (ef) (gh) a, (ab (ef) के लिए ) (gh) d, (ab) (ef) (gh) c, (ab) (cd) (gh) f, (ab) (cd) (gh) e, (ab) (cd) (ef) h (ab) (सीडी) (EF) जी]।


"सरणी में n संख्याओं को देखते हुए (आप यह नहीं मान सकते कि वे पूर्णांक हैं)," हम यह नहीं मान सकते हैं कि वे पूर्णांक हैं

5

ओ (एन लॉग एन) संचालन, स्कोर = 9974

एक द्विआधारी पेड़ के साथ काम करता है।

अजगर

l = list(map(int, input().split()))
n = len(l)

p = [0] * n + l
for i in range(n - 1, 1, -1):
  p[i] = p[i + i] * p[i + i+1]

def mul(x, y):
  if y == None:
    return x
  return x * y

r = [None] * n + [[None]] * n
for i in range(n - 1, 0, -1):
  r[i] = [mul(p[i + i + 1], x) for x in r[i + i]] + [mul(p[i + i], x) for x in r[i + i + 1]]

u = r[1]
j = 1
while j <= n:
  j += j
print(u[n+n-j:] + u[:n+n-j])

इसके लिए सूची जोड़ संचालन की आवश्यकता होती है, और संख्याओं पर कुछ अंकगणित जो कि इनपुट मान नहीं हैं; यकीन नहीं है कि अगर मायने रखता है। mulसमारोह वहाँ बचाने n संचालन आधार मामले के लिए, 1. से गुणा किसी भी मामले में करके उन्हें बर्बाद कर से बचने के लिए करने के लिए है, यह O (n n लॉग इन करें) आपरेशन है। सटीक सूत्र, अगर केवल इनपुट संख्या पर अंकगणितीय आपरेशनों गिनती, साथ j = floor(log_2(n)): j * (2^(j + 1) - n) + (j + 1) * (2 * n - 2^(j + 1)) - 2

बाहरी उत्पाद की गणना नहीं करने के विचार के साथ एक ऑपरेशन को बचाने के लिए @xnor के लिए धन्यवाद!

अंतिम भाग गुम अवधि के क्रम में उत्पादों का उत्पादन करना है।


यदि फॉर्मूला को ठीक से पूरा करना कठिन है, तो बेझिझक इसे केवल इसके लिए चलाएं n = 1000और कोड में अंकगणितीय संचालन की गणना करें।
आर्थर

मैंने 10975 ऑपरेशन गिनाए ...?
हाइपरनेत्रिनो

p[i] = p[i + i] * p[i + i+1]गिना नहीं जाता है
HyperNeutrino

यह n log2 n + nऑपरेशन के बारे में है (जो ओ (
नॉग्न

@HyperNeutrino को p[i] = p[i + i] * p[i + i + 1]गुणन अनुकूलन द्वारा सहेजा जाना चाहिए। मैं एक भी कई गिना जा सकता है, हालांकि।
nore

3

O ((n-2) * n) = O (n 2 ): तुच्छ समाधान

यह केवल तुच्छ समाधान है जो प्रत्येक उपसमुच्चय को एक साथ गुणा करता है:

अजगर

def product(array): # Requires len(array) - 1 multiplication operations
    if not array: return 1
    result = array[0]
    for value in array[1:]:
        result *= value
    return result

def getSubsetProducts(array):
    products = []
    for index in range(len(array)): # calls product len(array) times, each time calling on an array of size len(array) - 1, which means len(array) - 2 multiplication operations called len(array) times
        products.append(product(array[:index] + array[index + 1:]))
    return products

ध्यान दें कि इसके लिए nसूची-अतिरिक्त संचालन की भी आवश्यकता है ; यकीन नहीं है कि अगर मायने रखता है। यदि वह अनुमति नहीं है, तो product(array[:index] + array[index + 1:])उसे प्रतिस्थापित किया जा सकता है product(array[:index]) * product(array[index + 1:]), जो सूत्र को बदल देता है O((n-1)*n)


आप अपने खुद के स्कोर को उत्तर में जोड़ सकते हैं। इस मामले में 998 * 1000।
आर्थर

अपने productकार्य O(n)संचालन की जरूरत नहीं है ? सरणी में प्रत्येक तत्व के लिए एक (यह आसानी से बदला जा सकता है O(n-1))
रोमन ग्रैफ

@ रोमनग्रफ सच। मैं इसे O (n-1) में बदल दूंगा लेकिन इसे इंगित करने के लिए धन्यवाद।

इसे परमाणु-कोड-गोल्फ में बदल दिया गया है ...
एरिक द आउटगॉल्फ

@EriktheOutgolfer अब मेरा स्कोर क्या है? जब तक मैं स्पष्ट रूप से मूर्ख नहीं हो जाता, तब तक टैग और चश्मा एक दूसरे के विपरीत नहीं होते हैं?
हाइपरनेत्रिनो

3

पायथन, 7540

एक त्रिपक्षीय रणनीति का विलय करता है। मुझे लगता है कि मैं इससे भी बेहतर कर सकता हूं, एक बड़े विलय के साथ। यह O (n log n) है।

संपादित करें: एक मिसकाउंट फिक्स्ड।

count = 0
def prod(a, b):
    if a == 1: return b
    if b == 1: return a
    global count
    count += 1
    return a * b

def tri_merge(subs1, subs2, subs3):
    total1, missing1 = subs1
    total2, missing2 = subs2
    total3, missing3 = subs3

    prod12 = prod(total1, total2)
    prod13 = prod(total1, total3)
    prod23 = prod(total2, total3)

    new_missing1 = [prod(m1, prod23) for m1 in missing1]
    new_missing2 = [prod(m2, prod13) for m2 in missing2]
    new_missing3 = [prod(m3, prod12) for m3 in missing3]

    return prod(prod12, total3), new_missing1 + new_missing2 + new_missing3

def tri_partition(nums):
    split_size = len(nums) // 3
    a = nums[:split_size]
    second_split_length = split_size + (len(nums) % 3 == 2)
    b = nums[split_size:split_size + second_split_length]
    c = nums[split_size + second_split_length:]
    return a, b, c

def missing_products(nums):
    if len(nums) == 1: return nums[0], [1]
    if len(nums) == 0: return 1, []
    subs = [missing_products(part) for part in tri_partition(nums)]
    return tri_merge(*subs)

def verify(nums, res):
    actual_product = 1
    for num in nums:
        actual_product *= num
    actual_missing = [actual_product // num for num in nums]
    return actual_missing == res[1] and actual_product == res[0]

nums = range(2, int(input()) + 2)
res = missing_products(nums)

print("Verified?", verify(nums, res))
if max(res[1]) <= 10**10: print(res[1])

print(len(nums), count)

प्रासंगिक कार्य है missing_products, जो एक लापता तत्व के साथ समग्र उत्पाद और सभी को देता है।


क्या आपने गुणा में गिनती की tri_merge? इसके अलावा, आप बदल सकते हैं 2 * split_size + ...में tri_partitionसे split_size + split_size + ...
रोमन ग्रैफ

@ RomanGräf मैंने आपके सुझाव के अनुसार इसका पुनर्गठन किया।
इसहाक

1

डीसी, स्कोर 2994

#!/usr/bin/dc -f

# How it works:
# The required products are
#
#   (b × c × d × e × ... × x × y × z)
# (a) × (c × d × e × ... × x × y × z)
# (a × b) × (d × e × ... × x × y × z)
# ...
# (a × b × c × d × e × ... × x) × (z)
# (a × b × c × d × e × ... × x × y)
#
# We calculate each parenthesised term by
# multiplying the one above (on the left) or below
# (on the right), for 2(n-2) calculations, followed
# by the n-2 non-parenthesised multiplications
# giving a total of 3(n-2) operations.

# Read input from stdin
?

# We will store input values into stack 'a' and
# accumulated product into stack 'b'.  Initialise
# stack b with the last value read.
sb

# Turnaround function at limit of recursion: print
# accumulated 'b' value (containing b..z above).
[Lbn[ ]nq]sG

# Recursive function - on the way in, we stack up
# 'a' values and multiply up the 'b' values.  On
# the way out, we multiply up the 'a' values and
# multiply each by the corresponding 'b' value.
[dSalb*Sb
z1=G
lFx
dLb*n[ ]n
La*]dsFx

# Do the last a*b multiplication
dLb*n[ ]n

# And we have one final 'a' value that doesn't have a
# corresponding 'b':
La*n

मैं मान रहा हूँ कि पूर्णांक तुलना z1=(जो अंतिम मान तक पहुँचने पर पुनरावृत्ति को समाप्त करता है) मुक्त है। यह foreachअन्य भाषाओं की पसंद के बराबर है ।

प्रदर्शनों

for i in '2 3 5' '2 3 5 7' '0 2 3 5' '0 0 1 2 3 4'
do printf '%s => ' "$i"; ./127147.dc <<<"$i"; echo
done
2 3 5 => 15 10 6
2 3 5 7 => 105 70 42 30
0 2 3 5 => 30 0 0 0
0 0 1 2 3 4 => 0 0 0 0 0 0

बड़े और छोटे इनपुट के साथ एक डेमो:

./127147.dc <<<'.0000000000000000000542101086242752217003726400434970855712890625 1 18446744073709551616'
18446744073709551616 1.0000000000000000000000000000000000000000000000000000000000000000 .0000000000000000000542101086242752217003726400434970855712890625

1

C ++, स्कोर: 5990, O ([2NlogN] / 3)

यह कार्यान्वयन एक बाइनरी ट्री लुक अप टेबल का उपयोग करता है। मेरा पहला कार्यान्वयन O (NlogN) था, लेकिन एक अंतिम मिनट का अनुकूलन, जो सभी सरणी तत्वों के उत्पाद को घटाता है, एक जोड़ी को घटाता है, + 2 गुणा ने दिन बचाया। मुझे लगता है कि यह अभी भी थोड़ा और अनुकूलित किया जा सकता है, शायद एक और 16% ...

मैंने कुछ डिबगिंग निशान छोड़े हैं, केवल इसलिए कि उन्हें हटाने के लिए उन्हें फिर से लिखना आसान है :)

[संपादित करें] वास्तविक जटिलता को 100 के लिए O ([2NlogN] / 3) में मापा जाता है। यह वास्तव में छोटे सेटों के लिए O (NlogN) से थोड़ा खराब है, लेकिन सरणी बढ़ने पर O ([NlogN] / 2) की ओर झुक जाता है। 1 मिलियन तत्वों के सेट के लिए बहुत बड़ा ओ (0.57.NlogN)।

#include "stdafx.h"
#include <vector>
#include <iostream>
#include <random>
#include <cstdlib>

using DataType = long double;

using DataVector = std::vector<DataType>;

struct ProductTree
{
    std::vector<DataVector> tree_;
    size_t ops_{ 0 };

    ProductTree(const DataVector& v) : ProductTree(v.begin(), v.end()) {}
    ProductTree(DataVector::const_iterator first, DataVector::const_iterator last)
    {
        Build(first, last);
    }

    void Build(DataVector::const_iterator first, DataVector::const_iterator last)
    {
        tree_.emplace_back(DataVector(first, last));

        auto size = std::distance(first, last);
        for (auto n = size; n >= 2; n >>= 1)
        {
            first = tree_.back().begin();
            last = tree_.back().end();

            DataVector v;
            v.reserve(n);
            while (first != last) // steps in pairs
            {
                auto x = *(first++);
                if (first != last)
                {
                    ++ops_;
                    x *= *(first++); // could optimize this out,small gain
                }
                v.push_back(x);
            }
            tree_.emplace_back(v);
        }
    }

    // O(NlogN) implementation... 
    DataVector Prod()
    {
        DataVector result(tree_[0].size());
        for (size_t i = 0; i < tree_[0].size(); ++i)
        {
            auto depth = tree_.size() - 1;
            auto k = i >> depth;
            result[i] = ProductAtDepth(i, depth);
        }
        return result;
    }

    DataType ProductAtDepth(size_t index, size_t depth) 
    {
        if (depth == 0)
        {
            return ((index ^ 1) < tree_[depth].size())
                ? tree_[depth][index ^ 1]
                : 1;
        }
        auto k = (index >> depth) ^ 1;

        if ((k < tree_[depth].size()))
        {
            ++ops_;
            return tree_[depth][k] * ProductAtDepth(index, depth - 1);
        }
        return ProductAtDepth(index, depth - 1);
    }    

    // O([3NlogN]/2) implementation... 
    DataVector Prod2()
    {
        DataVector result(tree_[0].size());
        for (size_t i = 0; i < tree_[0].size(); ++i)    // steps in pairs
        {
            auto depth = tree_.size() - 1;
            auto k = i >> depth;
            auto x = ProductAtDepth2(i, depth);
            if (i + 1 < tree_[0].size())
            {
                ops_ += 2;
                result[i + 1] = tree_[0][i] * x;
                result[i] = tree_[0][i + 1] * x;
                ++i;
            }
            else
            {
                result[i] = x;
            }
        }
        return result;
    }

    DataType ProductAtDepth2(size_t index, size_t depth)
    {
        if (depth == 1)
        {
            index = (index >> 1) ^ 1;
            return (index < tree_[depth].size())
                ? tree_[depth][index]
                : 1;
        }
        auto k = (index >> depth) ^ 1;

        if ((k < tree_[depth].size()))
        {
            ++ops_;
            return tree_[depth][k] * ProductAtDepth2(index, depth - 1);
        }
        return ProductAtDepth2(index, depth - 1);
    }

};


int main()
{
    //srand(time());

    DataVector data;
    for (int i = 0; i < 1000; ++i)
    {
        auto x = rand() & 0x3;          // avoiding overflow and zero vaolues for testing
        data.push_back((x) ? x : 1);
    }

    //for (int i = 0; i < 6; ++i)
    //{
    //  data.push_back(i + 1);
    //}

    //std::cout << "data:[";
    //for (auto val : data)
    //{
    //  std::cout << val << ",";
    //}
    //std::cout << "]\n";

    ProductTree pt(data);
    DataVector result = pt.Prod2();

    //std::cout << "result:[";
    //for (auto val : result)
    //{
    //  std::cout << val << ",";
    //}
    //std::cout << "]\n";
    std::cout << "N = " << data.size() << " Operations :" << pt.ops_ << '\n';

    pt.ops_ = 0;
    result = pt.Prod();

    //std::cout << "result:[";
    //for (auto val : result)
    //{
    //  std::cout << val << ",";
    //}
    //std::cout << "]\n";

    std::cout << "N = " << data.size() << " Operations :" << pt.ops_ << '\n';

    return 0;
}

मैं पूर्णता के लिए @ nore का एल्गोरिथ्म जोड़ रहा हूं। यह वास्तव में अच्छा है, और सबसे तेज़ है।

class ProductFlat
{
private:
    size_t ops_{ 0 };

    void InitTables(const DataVector& v, DataVector& left, DataVector& right)
    {
        if (v.size() < 2)
        {
            return;
        }

        left.resize(v.size() - 1);
        right.resize(v.size() - 1);

        auto l = left.begin();
        auto r = right.rbegin();
        auto ol = v.begin();
        auto or = v.rbegin();

        *l = *ol++;
        *r = *or++;
        if (ol == v.end())
        {
            return;
        }

        while (ol + 1 != v.end())
        {
            ops_ += 2;
            *l = *l++ * *ol++;
            *r = *r++ * *or++;
        }
    }

public:
    DataVector Prod(const DataVector& v)
    {
        if (v.size() < 2)
        {
            return v;
        }

        DataVector result, left, right;
        InitTables(v, left, right);

        auto l = left.begin();
        auto r = right.begin();
        result.push_back(*r++);
        while (r != right.end())
        {
            ++ops_;
            result.push_back(*l++ * *r++);
        }
        result.push_back(*l++);
        return result;
    }

    auto Ops() const
    {
        return ops_;
    }
};
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.