2010-10-18 10 views
7

को देखते हुए संख्या n[1], n[2], n[3], .... n[x] का एक सेट और एक नंबर एमएल्गोरिथ्म संख्याओं के एक समूह का चयन करने के लिए एक न्यूनतम कुल

मैं

n[a] + n[b] + n[c] + ... + n[?] >= M 

संयोजन होना चाहिए का सबसे अच्छा संयोजन को खोजने के लिए चाहते हैं तक पहुँचने के लिए किसी भी अन्य संयोजन के साथ बेहतर परिणाम देने के साथ एम तक पहुंचने या जाने के लिए आवश्यक न्यूनतम तक पहुंचें।

PHP में ऐसा कर रहा है इसलिए PHP पुस्तकालयों का उपयोग ठीक है। यदि नहीं, तो बस एक सामान्य एल्गोरिदम करेगा। धन्यवाद!

+0

सबसे अच्छा उदाहरण मैं सोच सकता हूं कि एम मान के शॉपिंग वाउचर को देखते हुए, मैं एक स्टोर में जाता हूं और उत्पादों का चयन करता हूं जैसे कि मैं वाउचर का पूर्ण उपयोग करूँगा और शेष राशि को ऊपर उठाने के लिए न्यूनतम नकदी का भुगतान करूंगा। यदि मैं 1 से अधिक संयोजन उत्पन्न करता हूं जो समान कुल मूल्य उत्पन्न करता है तो मैं कम से कम उत्पादों के साथ संयोजन का चयन भी करूंगा। –

+0

चुनने के लिए उत्पादों की कम से कम राशि योग होगी {n [?] + N [c] + ...} जहां sum> एम। क्या मैं गलत हूं? – Chris

+0

इसकी राशि> = एम, प्राथमिकता सेट पर जा रही है जहां योग और एम के बीच का अंतर कम से कम है। यदि दो सेटों का एक ही योग है, तो कम से कम 'उत्पादों' के साथ सेट –

उत्तर

1
pseudocode: 

list<set> results; 
int m; 
list<int> a; 

// ...  

a.sort(); 

for each i in [0..a.size] 
    f(i, empty_set);  

// ... 

void f(int ind, set current_set) 
{ 
    current_set.add(a[ind]); 

    if (current_set.sum > m) 
    { 
     results.add(current_set); 
    } 
    else 
    { 
     for (int i=ind + 1; i<a.size; ++i) 
     { 
      f(i, current_set); // pass set by value 

      // if previous call reached solution, no need to continue 
      if (a[ind] + current_set.sum) > m 
       break; 
     } 
    } 
} 

// choose whatever "best" result you need from results, the one 
// with the lowest sum or lowest number of elements 
+0

दुर्भाग्यवश यह काम कर सकता है इष्टतम परिणाम वापस नहीं करता है। उदाहरण के लिए एम = 21, संख्या 22, 15, 5, 3, 2, 2, 1. यदि मैं गलत नहीं हूं, तो कोड 2 परिणाम [22] और [15, 5, 3, 2, 2]। लेकिन सबसे अच्छा जवाब [15,5,3,2,1] होगा जिसे नहीं माना जाएगा? अगर मैं यहाँ गलत हूं तो मुझे सही करो। –

+0

ने मामूली फिक्स जोड़ा, लेकिन एक और समस्या के लिए। उस समाधान को काम करना चाहिए, यह गलत शाखाओं के रूप में कटौती के सभी संभावित समाधानों पर निर्भर करता है। इसलिए आपके इनपुट के लिए यह [1, 2, 2, 3, 5, 15] [1, 2, 3, 5, 15] [1, 3, 5, 15] [1, 5, 15] [2, 2, 3, 5, 15] इत्यादि। सबसे कम योग या तत्वों की सबसे कम संख्या या जो भी आपका "सर्वश्रेष्ठ" मानदंड है, के साथ सेट चुनें। – Grozz

+0

इसे कोड में अनुवाद करने के लिए प्रबंधित किया गया। काफी अच्छी तरह से काम किया। धन्यवाद –

2

मुझे लगता है कि greedy algorithm दृष्टिकोण काम करेगा। सेट में आप कितने नंबरों की अपेक्षा करते हैं? यदि यह काफी कम है तो आप backtrack आज़मा सकते हैं, लेकिन मैं इसे बड़े सेट के लिए अनुशंसा नहीं करता।

+0

जीतता है धन्यवाद। में देख लूंगा। वर्तमान में, मैं अधिकतम 136 मूल्यों (भविष्य में वृद्धि की संभावना के साथ) के साथ एक सेट देख रहा हूं –

+0

आपको बैकट्रैक के लिए जाना चाहिए, लेकिन सेट को सॉर्ट करने और फिर बैकट्रैक में आने जैसी कुछ चालों का उपयोग करके निष्पादन समय में सुधार करने की कोशिश करना । अगर आपको मदद की ज़रूरत है तो मुझे बताएं –

+0

वर्तमान में, बैकट्रैक जाने का सबसे अच्छा तरीका दिखता है ... मुझे यह देखने के लिए थोड़ा और अध्ययन करना होगा कि यह काम करेगा या नहीं। धन्यवाद –

0

मुझे लगता है कि यह एनपी-पूर्ण है (सामान्य में करने का तेज़ तरीका ढूंढना संभव नहीं है)। जिस तरह से आपने प्रश्न का मूल्यांकन किया है, वह मुझे लक्ष्य Subset sum problems को एक लक्ष्य पूर्णांक के साथ हल करने के बारे में सोचता है जो एम

आपके उदाहरण में, यह निर्धारित करने की कोई ज्ञात विधि नहीं है कि एम तक पहुंचा जा सकता है या नहीं। केवल एक क्रूर बल समाधान आपको बताएगा कि यह संभव नहीं है, और केवल तभी आप एम + 1 की जांच कर सकते हैं।

हालांकि, आप डीपी solution पर विचार करना चाहेंगे, क्योंकि इससे आपको कम से कम समस्या का समाधान करने के बारे में एक विचार मिलेगा (हालांकि धीरे-धीरे)। approximate समाधान भी है जो आपकी संख्या छोटी होने पर सही होगा। इसका उपयोग करें। अंत में, यह इंगित करने लायक है कि समस्या का आकार बिट्स की संख्या में मापा जाता है, न कि सेट के आकार (या योग)।

जैसा ऊपर बताया गया है, यह Knapsack problem से संबंधित है।

1

इस तरह की समस्याओं को बाइनरी linear programming (पूर्णांक रैखिक प्रोग्रामिंग का एक विशेष मामला) कहा जाता है। यह प्रसिद्ध एनपी-हार्ड है - यानी सामान्य रूप से हल करने के लिए कुशल नहीं है।

हालांकि, वाणिज्यिक और मुफ्त उपयोग दोनों, अच्छे हलकों मौजूद हैं, उदाहरण के लिए ओपन सोर्स सॉल्वर lpsolve जिसे आप अपने प्रोग्राम से कॉल कर सकते हैं।

/संपादित करें: पुराना उत्तर बंक था। मैंने कारकों को भ्रमित कर दिया। साथ output_set = शून्य

algo(input_set , target_sum, output_set) 
    if input_set is NULL 
     error "target_sum can never be reached with all input_set" 
     return 
    the_max = maximum(input_set) 
    remove the_max from input_set 
    if the_max > target_sum 
     algo(input_set, target_sum, ouptput_set) 
     return 
    add the_max to output_set 
    algo(input_set, target_sum - the_max, output_set) 

कॉल:

+0

मुझे नहीं लगता कि यह एक रैखिक प्रोग्रामिंग समस्या है, क्योंकि आपके पास प्रत्येक संख्या का 0 या 1 हो सकता है, एक रैखिक प्रोग्रामिंग समस्या के साथ आप आंशिक गुणक –

+0

@ निक कर सकते हैं: अरे, आप सही हैं। यह एक बीएलपी है। –

-1

एक लालची समाधान एक छद्म काम करेगा। दक्षता के लिए सॉर्ट intput_set।

+0

ओप की समस्या का समाधान नहीं है। – Grozz

+0

मुझे लगता है कि यह समाधान केवल तभी काम करता है जब मैं मानों को बिल्कुल target_sum तक जोड़ना चाहता हूं। हालांकि, मेरे मामले के लिए, लक्ष्य_सम से परे कुल अनुमति है। –

0

यह समस्या लगभग subset sum problem है, जो Knapsack समस्या से संबंधित है लेकिन अलग है, और एनपी पूर्ण है। हालांकि, एक रैखिक समाधान होता है यदि सभी संख्याएं कुछ स्थिर से छोटी हैं, और एक बहुपद समय अनुमान है। उपरोक्त संदर्भित विकिपीडिया पेज देखें।

4

यह एक क्लासिक Dynamic Programming समस्या (भी अन्य उत्तर 0-1 बस्ता और सबसेट योग समस्याओं के साथ इसकी समानता का उल्लेख द्वारा इंगित) की तरह दिखता है।पूरी चीज एक साधारण पसंद तक उबालती है: सूची में प्रत्येक तत्व के लिए, क्या हम इसे अपने योग में उपयोग करते हैं या नहीं। के बाद से इस समारोह अतिव्यापी subproblems (यह एक ही subproblems बार बार की पड़ताल), यह एक अच्छा विचार के साथ समारोह memoize है है

f(index,target_sum)= 
    0  if target_sum<=0 (i.e. we don't need to add anymore) 
    infinity if target_sum>0 and index is past the length of n (i.e. we have run out of numbers to add) 
    min(f(index+1,target_sum), f(index+1,target_sum-n[index])+n[index]) otherwise (i.e. we explore two choices - 1. take the current number 2. skip over the current number and take their minimum) 

: हम जवाब गणना करने के लिए एक सरल पुनरावर्ती क्रिया ऊपर लिख सकते हैं पहले से गणना की गई मानों को पकड़ने के लिए एक कैश।

यहाँ अजगर में कोड है:

#! /usr/bin/env python 

INF=10**9 # a large enough number of your choice 

def min_sum(numbers,index,M, cache): 
    if M<=0: # we have reached or gone past our target, no need to add any more 
     return 0 
    elif len(numbers)==index: # we have run out of numbers, solution not possible 
     return INF 
    elif (index,M) in cache: # have been here before, just return the value we found earlier 
     return cache[(index,M)] 
    else: 
     answer=min(
      min_sum(numbers,index+1,M,cache), # skip over this value 
      min_sum(numbers,index+1,M-numbers[index],cache)+numbers[index] # use this value 
     ) 
     cache[(index,M)]=answer # store the answer so we can reuse it if needed 
     return answer 

if __name__=='__main__': 
    data=[10,6,3,100] 
    M=11 

    print min_sum(data,0,M,{}) 

यह समाधान केवल न्यूनतम राशि, न कि वास्तविक इसे बनाने के लिए इस्तेमाल किया तत्वों देता है। आप आसानी से अपने समाधान में जोड़ने के विचार को बढ़ा सकते हैं।

0

लालची समाधान काम करता है यदि प्रश्न कम से कम वस्तुओं की मांग करता है। लेकिन अधिकतम (..) फ़ंक्शन इस बात को ध्यान में रखेगा कि जब एम ऋणात्मक अधिकतम होता है तो उसे संख्या की दूरी 0 (abs() के मान को वापस करनी चाहिए)।

अधिकतम() फ़ंक्शन बाइनरी ढेर के माध्यम से कार्यान्वित किया जा सकता है। जटिलता ओ (एन। एलोग्न) है।

संबंधित मुद्दे