2012-12-21 17 views
5

मेरे पास एक सरणी है और इसकी लंबाई X है। सरणी के प्रत्येक तत्व में 1 .. L है। मैं सभी सरणी संयोजनों के माध्यम से कुशलता से पुन: प्रयास करना चाहता हूं जिसमें L है।निरंतर राशि के साथ सरणी संयोजनों के माध्यम से पुनरावृत्त कैसे करें?

के लिए सही समाधान: एल = 4 और एक्स = 2

1 3 
3 1 
2 2 

के लिए सही समाधान: एल = 5 और एक्स = 3

1 1 3 
1 3 1 
3 1 1 
1 2 2 
2 1 2 
2 2 1 

अनुभवहीन कार्यान्वयन है (कोई आश्चर्य नहीं) बहुत धीमी गति से मेरी समस्या के लिए (एक्स मेरे मामले में 8 तक है और एल 128 तक है)।

क्या कोई मुझे बता सकता है कि इस समस्या को कैसे कहा जाता है या समस्या के लिए तेज़ एल्गोरिदम कहां मिल सकता है?

धन्यवाद!

+2

यह मेरे लिए लग रहा है जैसे कि आप देख रहे हैं के लिए लंबाई 'एक्स' के' एल' के * पूर्णांक विभाजन *। –

+2

आप इसे * कुशलता से * नहीं कर सकते (साहित्य में, कुशलतापूर्वक = बहुपद रूप से)। समाधान की घातीय संख्याएं हैं, और उन सभी को फिर से शुरू करने के लिए घातीय समय की आवश्यकता है। – amit

+0

यह एक महान प्रोजेक्ट यूलर समस्या होगी =) –

उत्तर

8

अगर मैं सही ढंग से समझ, आप दो नंबर 1 ≤ एक्स दिया जाता है ≤ एल और आप एल को लंबाई एक्स कि राशि का धनात्मक पूर्णांक के सभी दृश्यों उत्पन्न करना चाहते हैं।

(नोट: यह integer partition problem के समान है, लेकिन ऐसा नहीं है, क्योंकि आप 1,2,2 से 2,2,2 से अलग अनुक्रम मानते हैं, जबकि पूर्णांक विभाजन समस्या में हम ऑर्डर को अनदेखा करते हैं, ताकि ये वही विभाजन माना जाता है)

दृश्यों कि आप की combinations एक्स से संबद्ध देख रहे हैं -। एल में से 1 आइटम - 1. के लिए, यदि हम संख्या डाल 1 एल - 1 क्रम में, और एक्स - उनमें से 1 चुनें, फिर चुने गए के बीच अंतराल की लंबाई संख्याएं सकारात्मक पूर्णांक हैं जो एल पर योग करती हैं।

उदाहरण के लिए, मान लीजिए कि एल 16 और एक्स है 5. फिर 1 से 15 समावेशी करने के लिए 4 नंबर का चयन है:

the four numbers 3, 7, 8, and 14 are chosen from 1 to 15

शुरुआत में 0 जोड़ें और 16 अंत में , और अंतराल हैं:

intervals 0–3, 3–7, 7–8, 8–14 and 14–16

और 3 + 4 + 1 + 6 + 2 = 16 के रूप में की आवश्यकता है। एल में से 1 आइटम - -

तो एक्स की generate the combinations 1, और हर एक के लिए, अंतराल का पता लगाकर एक विभाजन करने के लिए परिवर्तित। उदाहरण के लिए, पायथन में आप लिख सकते हैं:

from itertools import combinations 

def partitions(n, t): 
    """ 
    Generate the sequences of `n` positive integers that sum to `t`. 
    """ 
    assert(1 <= n <= t) 
    def intervals(c): 
     last = 0 
     for i in c: 
      yield i - last 
      last = i 
     yield t - last 
    for c in combinations(range(1, t), n - 1): 
     yield tuple(intervals(c)) 

>>> list(partitions(2, 4)) 
[(1, 3), (2, 2), (3, 1)] 
>>> list(partitions(3, 5)) 
[(1, 1, 3), (1, 2, 2), (1, 3, 1), (2, 1, 2), (2, 2, 1), (3, 1, 1)] 

हैं (एल - 1)!/(एक्स - 1)! (एल - एक्स)!एक्स के संयोजन - एल - 1 में से 1 आइटम, इसलिए इस एल्गोरिदम (और इसके आउटपुट का आकार) का रनटाइम एल में घातीय है। हालांकि, अगर आप आउटपुट की गणना नहीं करते हैं, तो इसे केवल ओ (एल) स्थान की आवश्यकता है।

एल के साथ

= 128 और एक्स = 8, ८९३५६४१५७७५ विभाजन देखते हैं, तो यह उन सब को उत्पादन के लिए कुछ समय ले जाएगा!

(हो सकता है कि अगर तुम तुम क्यों इन विभाजनों की गणना कर रहे हैं, हम वास्तव में उन सब का उत्पादन करने के बिना अपने आवश्यकताओं को पूरा करने के किसी तरह का सुझाव देने में सक्षम हो सकता समझाने।)

+0

मुझे लगता है कि यदि आप लूप से 'अंतराल' को स्थानांतरित करते हैं और इनपुट पैरामीटर के रूप में 'c' पास करते हैं तो इस कार्यान्वयन को थोड़ा अनुकूलित किया जा सकता है - इस तरह आप एक नया नहीं बना रहे हैं प्रत्येक संयोजन के लिए समारोह। – mgilson

+0

@mgilson: मैंने आपको खुश करने के लिए लूप के फ़ंक्शन परिभाषा को स्थानांतरित कर दिया। लेकिन इस तरह का अनुकूलन कार्यक्रम के घातीय रनटाइम व्यवहार के चेहरे में व्यर्थ दिखता है। इन विभाजनों को कंप्यूटिंग से बचने के तरीके को समझना बेहतर होगा। –

+0

मैं सहमत हूं - यह लगभग निराशाजनक कार्य के चेहरे में एक सुपर मामूली अनुकूलन है। लेकिन अगर हम इसके लिए एक कार्यान्वयन लिखने जा रहे हैं, तो यह भी एक अच्छा हो सकता है :-) – mgilson