N से k तत्वों के सभी संयोजनों को वापस करने के लिए एल्गोरिथम


571

मैं एक फ़ंक्शन लिखना चाहता हूं जो एक तर्क के रूप में अक्षरों की एक सरणी लेता है और चयन करने के लिए उन पत्रों की संख्या।

मान लें कि आप 8 अक्षरों की एक सरणी प्रदान करते हैं और उसमें से 3 अक्षरों का चयन करना चाहते हैं। तो आपको मिलना चाहिए:

8! / ((8 - 3)! * 3!) = 56

बदले में (या शब्द) प्रत्येक 3 अक्षरों से मिलकर बनता है।


2
प्रोग्रामिंग भाषा की कोई प्राथमिकता?
जोनाथन ट्रान

7
आप डुप्लिकेट पत्रों से कैसे निपटना चाहते हैं?
wcm

भाषा की कोई प्राथमिकता नहीं, मैं इसे माणिक में कोड करने जा रहा हूं, लेकिन जो एल्गोरिदम का उपयोग करने का एक सामान्य विचार है वह ठीक होगा। एक ही मूल्य के दो अक्षर मौजूद हो सकते हैं लेकिन एक ही अक्षर के दो बार नहीं।
फ्रेड्रिक


Php में, निम्नलिखित चाल को करना चाहिए: stackoverflow.com/questions/4279722/…
केमल दा

जवाबों:


412

आर्ट ऑफ़ कंप्यूटर प्रोग्रामिंग वॉल्यूम 4: फ़ासिकल 3 में इनमें से एक टन है जो आपके विशेष स्थिति को मेरे वर्णन से बेहतर हो सकता है।

ग्रे कोड्स

एक मुद्दा जो आपके सामने आएगा वह निश्चित रूप से स्मृति और बहुत जल्दी है, आपको अपने सेट में 20 तत्वों द्वारा समस्याएं होंगी - 20 सी 3 = 1140. और यदि आप सेट पर पुनरावृति करना चाहते हैं तो संशोधित ग्रे का उपयोग करना सबसे अच्छा है कोड एल्गोरिथ्म तो आप स्मृति में उन सभी को पकड़ नहीं रहे हैं। ये पिछले से अगला संयोजन उत्पन्न करते हैं और दोहराव से बचते हैं। विभिन्न उपयोगों के लिए इनमें से कई हैं। क्या हम क्रमिक संयोजनों के बीच अंतर को अधिकतम करना चाहते हैं? छोटा करना? et cetera

ग्रे कोड्स का वर्णन करने वाले कुछ मूल कागजात:

  1. कुछ हैमिल्टन पथ और एक न्यूनतम परिवर्तन एल्गोरिथम
  2. आसन्न इंटरचेंज संयोजन संयोजन एल्गोरिथ्म

इस विषय को कवर करने वाले कुछ अन्य कागजात हैं:

  1. Eades के एक कुशल कार्यान्वयन, Hickey, निकटवर्ती इंटरचेंज संयोजन पीढ़ी एल्गोरिदम पढ़ें (पीडीएफ, पास्कल में कोड के साथ)
  2. संयोजन जनक
  3. कॉम्बिनेटर ग्रे कोड्स (पोस्टस्क्रिप्ट) का सर्वेक्षण
  4. ग्रे कोड्स के लिए एक एल्गोरिथम

चेस ट्वीडल (एल्गोरिथम)

फिलिप जे चेज़, ` एल्गोरिथम 382: एम आउट ऑफ एन ऑब्जेक्ट्स ’ (1970)

सी में एल्गोरिथ्म ...

लेक्सोग्राफिक ऑर्डर में संयोजन का सूचकांक (बकस एल्गोरिथ्म 515)

आप इसके सूचकांक द्वारा एक संयोजन का संदर्भ भी दे सकते हैं (लेक्सिकोग्राफ़िक क्रम में)। यह महसूस करते हुए कि सूचकांक के आधार पर सूचकांक में दाईं ओर से बाईं ओर कुछ बदलाव होना चाहिए, हम कुछ का निर्माण कर सकते हैं जो एक संयोजन को पुनर्प्राप्त करना चाहिए।

तो, हमारे पास एक सेट {1,2,3,4,5,6} है ... और हम तीन तत्व चाहते हैं। मान लें कि {1,2,3} हम कह सकते हैं कि तत्वों के बीच अंतर एक और क्रम में और न्यूनतम है। {1,2,4} में एक परिवर्तन है और लेक्सोग्राफिक रूप से नंबर 2 है। इसलिए लेक्सोग्राफिक ऑर्डरिंग में एक परिवर्तन के लिए अंतिम स्थान में 'परिवर्तन' की संख्या है। एक परिवर्तन {1,3,4} के साथ दूसरे स्थान पर एक परिवर्तन है, लेकिन अधिक परिवर्तन के लिए जिम्मेदार है क्योंकि यह दूसरे स्थान पर है (मूल सेट में तत्वों की संख्या के अनुपात में)।

जिस विधि का मैंने वर्णन किया है वह एक डिकंस्ट्रक्शन है, जैसा कि ऐसा लगता है, सेट से इंडेक्स तक, हमें रिवर्स करने की आवश्यकता है - जो बहुत पेचीदा है। इस तरह से बकल्स समस्या का हल करता है। मैंने कुछ सी लिखने के लिए उन्हें मामूली बदलावों के साथ गणना की - मैंने सेट का प्रतिनिधित्व करने के लिए एक संख्या सीमा के बजाय सेट के सूचकांक का उपयोग किया, इसलिए हम हमेशा 0 ... n से काम कर रहे हैं। ध्यान दें:

  1. चूंकि संयोजन अनियंत्रित होते हैं, {1,3,2} = {1,2,3} - हम उन्हें लेक्सोग्राफ़िक होने का आदेश देते हैं।
  2. इस विधि में पहले अंतर के लिए सेट शुरू करने के लिए एक निहित 0 है।

लेक्सोग्राफिक ऑर्डर में संयोजन का सूचकांक (मैकक्रेफ)

एक और तरीका है : इसकी अवधारणा को समझ और प्रोग्राम करना आसान है, लेकिन यह बकल के अनुकूलन के बिना है। सौभाग्य से, यह भी नकली संयोजनों का उत्पादन नहीं करता है:

वह सेट जहां x_k ... x_1 एन मेंअधिकतम होता है i = C (x_1, k) + C (x_2, k-1) + ... + C (x_k, 1), जहां C (n, r) = {n चुनें r}

एक उदाहरण के लिए 27 = C(6,4) + C(5,3) + C(2,2) + C(1,1):। तो, चार चीजों का २ le वाँ कोशिक संयोजन है: {१,२,५,६}, वे जो भी सेट आप देखना चाहते हैं, उनके सूचकांक हैं। नीचे उदाहरण (OCaml), chooseफ़ंक्शन की आवश्यकता है, पाठक के लिए छोड़ दिया गया है:

(* this will find the [x] combination of a [set] list when taking [k] elements *)
let combination_maccaffery set k x =
    (* maximize function -- maximize a that is aCb              *)
    (* return largest c where c < i and choose(c,i) <= z        *)
    let rec maximize a b x =
        if (choose a b ) <= x then a else maximize (a-1) b x
    in
    let rec iterate n x i = match i with
        | 0 -> []
        | i ->
            let max = maximize n i x in
            max :: iterate n (x - (choose max i)) (i-1)
    in
    if x < 0 then failwith "errors" else
    let idxs =  iterate (List.length set) x k in
    List.map (List.nth set) (List.sort (-) idxs)

एक छोटा और सरल संयोजन पुनरावृत्ति

निम्नलिखित दो एल्गोरिदम दिमागी उद्देश्यों के लिए प्रदान किए जाते हैं। वे एक पुनरावृत्ति और (अधिक सामान्य) फ़ोल्डर समग्र संयोजनों को लागू करते हैं। वे ओ ( एन सी के ) की जटिलता वाले होने के रूप में तेजी से संभव हैं । स्मृति खपत द्वारा बाध्य है k

हम इट्रेटर के साथ शुरू करेंगे, जो प्रत्येक संयोजन के लिए एक उपयोगकर्ता प्रदान किए गए फ़ंक्शन को कॉल करेगा

let iter_combs n k f =
  let rec iter v s j =
    if j = k then f v
    else for i = s to n - 1 do iter (i::v) (i+1) (j+1) done in
  iter [] 0 0

एक अधिक सामान्य संस्करण प्रारंभिक अवस्था से शुरू होने वाले राज्य चर के साथ उपयोगकर्ता प्रदान किए गए फ़ंक्शन को कॉल करेगा। चूंकि हमें अलग-अलग राज्यों के बीच राज्य को पारित करने की आवश्यकता है, हम फॉर-लूप का उपयोग नहीं करेंगे, लेकिन इसके बजाय, पुनरावर्तन का उपयोग करें,

let fold_combs n k f x =
  let rec loop i s c x =
    if i < n then
      loop (i+1) s c @@
      let c = i::c and s = s + 1 and i = i + 1 in
      if s < k then loop i s c x else f c x
    else x in
  loop 0 0 [] x

1
क्या यह उस मामले में डुप्लिकेट संयोजनों का उत्पादन करेगा जहां सेट में समान तत्व होते हैं?
थॉमस अहले

2
हाँ, यह थॉमस होगा। यह सरणी में डेटा के लिए अज्ञेय है। आप हमेशा डुप्लिकेट को पहले फ़िल्टर कर सकते हैं, यदि यह वांछित प्रभाव है, या किसी अन्य एल्गोरिथ्म को चुनना है।
मुलुकरौनी

19
बहुत बढ़िया जवाब। क्या आप प्रत्येक एल्गोरिदम के लिए रन टाइम और मेमोरी विश्लेषण का सारांश प्रदान कर सकते हैं?
अनकैप्ड_एक्सपेक्शन

2
बहुत अच्छा जवाब। 20C3 1140 है, विस्मयादिबोधक चिह्न यहाँ भ्रमित कर रहा है क्योंकि यह एक गुटीय जैसा दिखता है, और गुटबाजी संयोजन खोजने के सूत्र में प्रवेश करते हैं। इसलिए मैं विस्मयादिबोधक चिह्न को संपादित करूंगा।
कैशबैक

3
यह बेकार है कि कई उद्धरण एक paywall के पीछे हैं। क्या गैर-भुगतान लिंक को शामिल करने या स्रोतों से उद्धरण योग्य स्निपेट शामिल करने की संभावना है?
टेरेंस

195

C # में:

public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int k)
{
  return k == 0 ? new[] { new T[0] } :
    elements.SelectMany((e, i) =>
      elements.Skip(i + 1).Combinations(k - 1).Select(c => (new[] {e}).Concat(c)));
}

उपयोग:

var result = Combinations(new[] { 1, 2, 3, 4, 5 }, 3);

परिणाम:

123
124
125
134
135
145
234
235
245
345

2
यह समाधान "छोटे" सेट के लिए अच्छी तरह से काम करता है लेकिन बड़े सेट के लिए यह थोड़ी मेमोरी का उपयोग करता है।
आर्टूर कार्वाल्हो

1
सीधे संबंधित नहीं है, लेकिन कोड बहुत ही रोचक / पठनीय है और मुझे आश्चर्य है कि c # के कौन से संस्करण में यह निर्माण / विधियाँ हैं? (मैंने केवल c # v1.0 का उपयोग किया है और उतना नहीं)।
LBarret

निश्चित रूप से सुंदर, लेकिन IEnumerable एक प्रगणित किया जाएगा बहुत समय की। अगर यह कुछ महत्वपूर्ण ऑपरेशन द्वारा समर्थित है ...
ड्रू नोक

2
चूँकि यह एक विस्तार विधि है var result = new[] { 1, 2, 3, 4, 5 }.Combinations(3);
जिससे

1
क्या आप पुनरावर्ती छोरों का उपयोग करके इस क्वेरी का सटीक गैर
लाइनक

81

लघु जावा समाधान:

import java.util.Arrays;

public class Combination {
    public static void main(String[] args){
        String[] arr = {"A","B","C","D","E","F"};
        combinations2(arr, 3, 0, new String[3]);
    }

    static void combinations2(String[] arr, int len, int startPosition, String[] result){
        if (len == 0){
            System.out.println(Arrays.toString(result));
            return;
        }       
        for (int i = startPosition; i <= arr.length-len; i++){
            result[result.length - len] = arr[i];
            combinations2(arr, len-1, i+1, result);
        }
    }       
}

रिजल्ट होगा

[A, B, C]
[A, B, D]
[A, B, E]
[A, B, F]
[A, C, D]
[A, C, E]
[A, C, F]
[A, D, E]
[A, D, F]
[A, E, F]
[B, C, D]
[B, C, E]
[B, C, F]
[B, D, E]
[B, D, F]
[B, E, F]
[C, D, E]
[C, D, F]
[C, E, F]
[D, E, F]

यह O (n ^ 3) सही लगता है? मुझे आश्चर्य है कि ऐसा करने के लिए एक तेज एल्गोरिथम है।
लेज़ो

मैं 20 चुनिंदा 10 के साथ काम कर रहा हूं और यह मेरे लिए काफी तेज है (1 सेकंड से भी कम)
डिमॉन्गोलेम

4
@ नैनो तुम गलत हो। यह पुनरावृत्ति के बिना संयोजन है। और आपका मामला दोहराव के साथ है।
जैक द रिपर

कोड का यह टुकड़ा वेब पर ढूंढना आसान होना चाहिए ... यह वही है जो मैं देख रहा था!
मैनुअल एस।

मैंने इसे और 7 अन्य जावा कार्यान्वयनों का परीक्षण किया - यह अब तक का सबसे तेज था। दूसरा सबसे तेज़, धीमेपन के क्रम से अधिक था।
स्टुअर्ट

77

क्या मैं इस समस्या के लिए अपने पुनरावर्ती पायथन समाधान प्रस्तुत कर सकता हूं?

def choose_iter(elements, length):
    for i in xrange(len(elements)):
        if length == 1:
            yield (elements[i],)
        else:
            for next in choose_iter(elements[i+1:len(elements)], length-1):
                yield (elements[i],) + next
def choose(l, k):
    return list(choose_iter(l, k))

उदाहरण उपयोग:

>>> len(list(choose_iter("abcdefgh",3)))
56

मुझे इसकी सादगी पसंद है।


16
len(tuple(itertools.combinations('abcdefgh',3)))कम कोड वाले पायथन में एक ही चीज हासिल करेंगे।
hgus1294

59
@ hgus1294 सच है, लेकिन यह धोखा होगा। Op ने एक एल्गोरिथ्म का अनुरोध किया, न कि "जादू" पद्धति का जो एक विशेष प्रोग्रामिंग भाषा से जुड़ा हुआ है।
MestreLion

1
पहले लूप रेंज को कड़ाई से नहीं बोलना चाहिए for i in xrange(len(elements) - length + 1):? अजगर में कोई फर्क नहीं पड़ता है क्योंकि स्लाइस इंडेक्स से बाहर जाने के लिए इनायत होती है लेकिन यह सही एल्गोरिथम है।
स्टीफन डॉलबर्ग

62

कहते हैं कि अक्षरों की आपकी सरणी इस तरह दिखती है: "ABCDEFGH"। आपके पास तीन सूचक हैं (i, j, k) जो दर्शाता है कि आप वर्तमान शब्द के लिए किन अक्षरों का उपयोग करने जा रहे हैं, आप इसके साथ शुरू करते हैं:

ABCDEFGH
^ ^ ^
IJK

पहले आप k भिन्न होते हैं, इसलिए अगला चरण ऐसा दिखता है:

ABCDEFGH
^ ^ ^
IJK

यदि आप अंत तक पहुँच गए हैं तो आप आगे बढ़ते हैं और फिर j और उसके बाद k फिर से बदलते हैं।

ABCDEFGH
^ ^ ^
IJK

ABCDEFGH
^ ^ ^
IJK

एक बार जब आप जी तक पहुँच गए तो आप भी मुझे अलग करना शुरू कर देंगे।

ABCDEFGH
  ^ ^ ^
  IJK

ABCDEFGH
  ^ ^ ^
  IJK
...

कोड में लिखा यह कुछ इस तरह दिखता है

void print_combinations(const char *string)
{
    int i, j, k;
    int len = strlen(string);

    for (i = 0; i < len - 2; i++)
    {
        for (j = i + 1; j < len - 1; j++)
        {
            for (k = j + 1; k < len; k++)
                printf("%c%c%c\n", string[i], string[j], string[k]);
        }
    }
}

115
इस दृष्टिकोण के साथ समस्या यह है कि यह कोड में पैरामीटर 3 को हार्ड-वायर करता है। (क्या होगा यदि 4 वर्ण वांछित थे?) जैसा कि मैंने प्रश्न को समझा है, वर्णों की सरणी और चयन करने के लिए वर्णों की संख्या प्रदान की जाएगी। बेशक, उस मुद्दे के आसपास एक तरह से पुनरावृत्ति के साथ स्पष्ट रूप से नेस्टेड छोरों को बदलना है।
joel.neely

10
@ Dr.PersonPersonII और ओपी के लिए किसी भी प्रासंगिकता के त्रिकोण क्यों हैं?
MestreLion

7
आप हमेशा इस समाधान को मनमाने ढंग से पैरामीटर के साथ पुनरावृत्ति करने के लिए बदल सकते हैं।
रोक क्राल

5
@RokKralj, हम कैसे "इस समाधान को मनमाने ढंग से पैरामीटर के साथ पुनरावृत्ति करने के लिए परिवर्तित करते हैं"? मेरे लिए असंभव लगता है।
एरॉन मैकडैड

3
यह कैसे करना है की एक अच्छी सहज व्याख्या
Yonatan Simson

53

निम्नलिखित पुनरावर्ती एल्गोरिथ्म सभी k- तत्व संयोजनों को एक निर्धारित सेट से चुनता है:

  • iअपने संयोजन का पहला तत्व चुनें
  • गठबंधन iके संयोजन से प्रत्येक के साथ k-1की तुलना में बड़ा तत्वों के सेट से रिकर्सिवली चुना तत्वों i

iसेट में प्रत्येक के लिए ऊपर बताएं ।

यह आवश्यक है कि आप iपुनरावृत्ति से बचने के लिए बाकी तत्वों को जितना बड़ा हो सके , उठाएं। इस तरह से [3,5] केवल एक बार ही उठाया जाएगा, क्योंकि [3] को [5] के साथ जोड़कर, दो बार के बजाय (स्थिति [5] + [3] समाप्त कर देता है)। इस स्थिति के बिना आपको संयोजनों के बजाय विविधताएं मिलती हैं।


12
बहुत सारे उत्तरों द्वारा उपयोग किए गए एल्गोरिथ्म की अंग्रेजी में बहुत अच्छा वर्णन
MestreLion

दूसरा ऊपर; विशेष रूप से, इससे मुझे user935714 द्वारा हल किए गए समाधान को समझने में मदद मिली। दोनों ही बेहतरीन हैं।
जैकबलामबर्ट

25

C ++ में निम्नलिखित दिनचर्या रेंज [प्रथम, अंतिम) के बीच लंबाई दूरी (पहले, k) के सभी संयोजनों का उत्पादन करेगी:

#include <algorithm>

template <typename Iterator>
bool next_combination(const Iterator first, Iterator k, const Iterator last)
{
   /* Credits: Mark Nelson http://marknelson.us */
   if ((first == last) || (first == k) || (last == k))
      return false;
   Iterator i1 = first;
   Iterator i2 = last;
   ++i1;
   if (last == i1)
      return false;
   i1 = last;
   --i1;
   i1 = k;
   --i2;
   while (first != i1)
   {
      if (*--i1 < *i2)
      {
         Iterator j = k;
         while (!(*i1 < *j)) ++j;
         std::iter_swap(i1,j);
         ++i1;
         ++j;
         i2 = k;
         std::rotate(i1,j,last);
         while (last != j)
         {
            ++j;
            ++i2;
         }
         std::rotate(k,i2,last);
         return true;
      }
   }
   std::rotate(first,k,last);
   return false;
}

इसका उपयोग इस तरह किया जा सकता है:

#include <string>
#include <iostream>

int main()
{
    std::string s = "12345";
    std::size_t comb_size = 3;
    do
    {
        std::cout << std::string(s.begin(), s.begin() + comb_size) << std::endl;
    } while (next_combination(s.begin(), s.begin() + comb_size, s.end()));

    return 0;
}

यह निम्नलिखित प्रिंट करेगा:

123
124
125
134
135
145
234
235
245
345

1
क्या शुरू होता है, इस मामले में क्या अंत है? यदि वास्तव में इस फ़ंक्शन को दिए गए सभी चर मान द्वारा पारित किए जाते हैं तो यह वास्तव में कुछ कैसे लौटा सकता है?
फ्रैंकफर्ट पापनेव

6
@ सार्जेंट पापेव: बदलें beingऔर beginसाथ s.begin(), और endसाथ s.end()। कोड एसटीएल के next_permutationएल्गोरिथ्म का बारीकी से अनुसरण करता है, जिसे यहां अधिक विवरण में वर्णित किया गया है
एंथनी लैबरा

5
क्या हो रहा है? i1 = अंतिम; --i1; i1 = k;
मनोज आर

24

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

function string_recurse(active, rest) {
    if (rest.length == 0) {
        console.log(active);
    } else {
        string_recurse(active + rest.charAt(0), rest.substring(1, rest.length));
        string_recurse(active, rest.substring(1, rest.length));
    }
}
string_recurse("", "abc");

आउटपुट निम्नानुसार होना चाहिए:

abc
ab
ac
a
bc
b
c

4
@ नैनोहेड यह गलत नहीं है। आउटपुट पहले से ही "एसी" दिखाता है - और "सीए" "एसी" के समान संयोजन है । आप क्रमपरिवर्तन के बारे में बात कर रहे हैं (गणित में) जहां "एसी" "सीए" के समान नहीं होगा।
जैकब जेनकोव

1
यह n च k नहीं है।
shinzou

20
static IEnumerable<string> Combinations(List<string> characters, int length)
{
    for (int i = 0; i < characters.Count; i++)
    {
        // only want 1 character, just return this one
        if (length == 1)
            yield return characters[i];

        // want more than one character, return this one plus all combinations one shorter
        // only use characters after the current one for the rest of the combinations
        else
            foreach (string next in Combinations(characters.GetRange(i + 1, characters.Count - (i + 1)), length - 1))
                yield return characters[i] + next;
    }
}

अच्छा समाधान। मैंने इस हालिया प्रश्न के उत्तर में इसका उल्लेख किया: stackoverflow.com/questions/4472036/…
wageoghe

इस फ़ंक्शन के साथ एकमात्र समस्या पुनरावृत्ति है। हालांकि यह आमतौर पर पीसी पर चलने वाले सॉफ़्टवेयर के लिए ठीक है, यदि आप एक अधिक संसाधन युक्त मंच (उदाहरण के लिए एम्बेडेड) के साथ काम कर रहे हैं, तो आप भाग्य से बाहर हैं
Padu Merloti

यह बहुत सारी सूचियों को भी आवंटित करेगा और प्रत्येक नए में सरणी के आइटम की नकल करने के लिए बहुत सारे काम करेगा। यह मुझे लगता है कि जब तक पूरी गणना पूरी नहीं हो जाती तब तक ये सूचियाँ संग्रहणीय नहीं होंगी।
Niall Connaughton

वह चालाक है। क्या आपको एक एल्गोरिथ्म मिला या वह खरोंच से है?
पापराज़ो

20

पायथन में लघु उदाहरण:

def comb(sofar, rest, n):
    if n == 0:
        print sofar
    else:
        for i in range(len(rest)):
            comb(sofar + rest[i], rest[i+1:], n-1)

>>> comb("", "abcde", 3)
abc
abd
abe
acd
ace
ade
bcd
bce
bde
cde

स्पष्टीकरण के लिए, पुनरावर्ती विधि निम्नलिखित उदाहरण के साथ वर्णित है:

उदाहरण: ABCDE
3 के सभी संयोजन होंगे:

  • बाकी (BCDE) से 2 के सभी संयोजनों के साथ
  • बाकी (सीडीई) से 2 के सभी संयोजनों के साथ बी
  • बाकी के 2 से सभी संयोजनों के साथ C (DE)

17

हास्केल में सरल पुनरावर्ती एल्गोरिदम

import Data.List

combinations 0 lst = [[]]
combinations n lst = do
    (x:xs) <- tails lst
    rest   <- combinations (n-1) xs
    return $ x : rest

हम पहले विशेष मामले को परिभाषित करते हैं, अर्थात शून्य तत्वों का चयन करना। यह एक परिणाम उत्पन्न करता है, जो एक खाली सूची है (यानी एक सूची जिसमें एक खाली सूची है)।

N> 0 के लिए, xसूची के प्रत्येक तत्व के माध्यम से जाता है और xsप्रत्येक तत्व के बाद हैx

restएक पुनरावर्ती कॉल का उपयोग करने n - 1से तत्वों को उठाता xsहै combinations। समारोह के अंतिम परिणाम एक सूची प्रत्येक तत्व का है x : rest(यानी एक सूची जो xप्रमुख के रूप में और restके हर अलग मूल्य के लिए पूंछ के रूप में) xऔर rest

> combinations 3 "abcde"
["abc","abd","abe","acd","ace","ade","bcd","bce","bde","cde"]

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

> let c = combinations 8 "abcdefghijklmnopqrstuvwxyz"
> take 10 c
["abcdefgh","abcdefgi","abcdefgj","abcdefgk","abcdefgl","abcdefgm","abcdefgn",
 "abcdefgo","abcdefgp","abcdefgq"]

13

और यहाँ दादाजी COBOL आता है, जो बहुत ही बदनाम भाषा है।

आइए प्रत्येक 8 बाइट्स के 34 तत्वों की एक सरणी मान लें (विशुद्ध रूप से मनमाने ढंग से चयन।) यह विचार सभी संभावित 4-तत्व संयोजनों की गणना करना और उन्हें एक सरणी में लोड करना है।

हम 4 सूचकांकों का उपयोग करते हैं, प्रत्येक 4 के समूह में प्रत्येक स्थिति के लिए

सरणी इस प्रकार संसाधित होती है:

    idx1 = 1
    idx2 = 2
    idx3 = 3
    idx4 = 4

हम idx4 को 4 से अंत तक बदलते हैं। प्रत्येक idx4 के लिए हमें चार के समूहों का एक अनूठा संयोजन मिलता है। जब idx4 सरणी के अंत में आता है, तो हम idx3 को 1 से बढ़ाते हैं और idx4 को idx3 + 1 पर सेट करते हैं। फिर हम फिर से अंत तक idx4 चलाते हैं। हम इस तरीके से आगे बढ़ते हैं, idx3, idx2 और idx1 को क्रमशः बढ़ाते हैं जब तक कि idx1 की स्थिति सरणी के अंत से 4 से कम नहीं है। जो कि एल्गोरिथम को पूरा करता है।

1          --- pos.1
2          --- pos 2
3          --- pos 3
4          --- pos 4
5
6
7
etc.

पहली पुनरावृत्तियों:

1234
1235
1236
1237
1245
1246
1247
1256
1257
1267
etc.

एक COBOL उदाहरण:

01  DATA_ARAY.
    05  FILLER     PIC X(8)    VALUE  "VALUE_01".
    05  FILLER     PIC X(8)    VALUE  "VALUE_02".
  etc.
01  ARAY_DATA    OCCURS 34.
    05  ARAY_ITEM       PIC X(8).

01  OUTPUT_ARAY   OCCURS  50000   PIC X(32).

01   MAX_NUM   PIC 99 COMP VALUE 34.

01  INDEXXES  COMP.
    05  IDX1            PIC 99.
    05  IDX2            PIC 99.
    05  IDX3            PIC 99.
    05  IDX4            PIC 99.
    05  OUT_IDX   PIC 9(9).

01  WHERE_TO_STOP_SEARCH          PIC 99  COMP.

* Stop the search when IDX1 is on the third last array element:

COMPUTE WHERE_TO_STOP_SEARCH = MAX_VALUE - 3     

MOVE 1 TO IDX1

PERFORM UNTIL IDX1 > WHERE_TO_STOP_SEARCH
   COMPUTE IDX2 = IDX1 + 1
   PERFORM UNTIL IDX2 > MAX_NUM
      COMPUTE IDX3 = IDX2 + 1
      PERFORM UNTIL IDX3 > MAX_NUM
         COMPUTE IDX4 = IDX3 + 1
         PERFORM UNTIL IDX4 > MAX_NUM
            ADD 1 TO OUT_IDX
            STRING  ARAY_ITEM(IDX1)
                    ARAY_ITEM(IDX2)
                    ARAY_ITEM(IDX3)
                    ARAY_ITEM(IDX4)
                    INTO OUTPUT_ARAY(OUT_IDX)
            ADD 1 TO IDX4
         END-PERFORM
         ADD 1 TO IDX3
      END-PERFORM
      ADD 1 TO IDX2
   END_PERFORM
   ADD 1 TO IDX1
END-PERFORM.

लेकिन क्यों {} {} {} {}
shinzou

9

यहाँ स्केल में एक सुरुचिपूर्ण, सामान्य कार्यान्वयन है, जैसा कि 99 स्काला समस्याओं पर वर्णित है ।

object P26 {
  def flatMapSublists[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] = 
    ls match {
      case Nil => Nil
      case sublist@(_ :: tail) => f(sublist) ::: flatMapSublists(tail)(f)
    }

  def combinations[A](n: Int, ls: List[A]): List[List[A]] =
    if (n == 0) List(Nil)
    else flatMapSublists(ls) { sl =>
      combinations(n - 1, sl.tail) map {sl.head :: _}
    }
}

9

यदि आप SQL सिंटैक्स का उपयोग कर सकते हैं - कह सकते हैं, यदि आप किसी संरचना या सरणी के क्षेत्रों तक पहुँचने के लिए LINQ का उपयोग कर रहे हैं, या सीधे एक डेटाबेस को एक्सेस कर रहे हैं जिसमें "वर्णमाला" नामक एक तालिका है जिसमें केवल एक चार फ़ील्ड "लेटर" है, तो आप इसे अनुकूलित कर सकते हैं कोड:

SELECT A.Letter, B.Letter, C.Letter
FROM Alphabet AS A, Alphabet AS B, Alphabet AS C
WHERE A.Letter<>B.Letter AND A.Letter<>C.Letter AND B.Letter<>C.Letter
AND A.Letter<B.Letter AND B.Letter<C.Letter

यह 3 अक्षरों के सभी संयोजनों को लौटाएगा, भले ही आपके पास "वर्णमाला" में कितने अक्षर हों (यह 3, 8, 10, 27, आदि हो सकते हैं)।

यदि आप चाहते हैं कि सभी क्रमपरिवर्तन हों, तो संयोजन के बजाय (यानी आप "एसीबी" और "एबीसी" को अलग-अलग गिनना चाहते हैं, बल्कि केवल एक बार दिखाई देना) बस अंतिम पंक्ति (और एक) को हटा दें और यह हो गया।

पोस्ट-एडिट: प्रश्न को फिर से पढ़ने के बाद, मुझे एहसास होता है कि सामान्य एल्गोरिथ्म की आवश्यकता है , न कि केवल 3 आइटमों के चयन के मामले के लिए एक विशिष्ट। एडम ह्यूजेस का उत्तर पूर्ण है, दुर्भाग्य से मैं इसे (अभी तक) वोट नहीं दे सकता। यह उत्तर सरल है, लेकिन केवल तब काम करता है जब आप वास्तव में 3 आइटम चाहते हैं।


7

संयोजन सूचक की आलसी पीढ़ी के साथ एक और सी # संस्करण। यह संस्करण सभी मानों की सूची और वर्तमान संयोजन के लिए मानों के बीच मानचित्रण को परिभाषित करने के लिए सूचकांकों का एक एकल सरणी रखता है, अर्थात पूरे रनटाइम के दौरान लगातार ओ (के) अतिरिक्त स्थान का उपयोग करता है। कोड ओ (के) समय में पहले एक सहित व्यक्तिगत संयोजन उत्पन्न करता है।

public static IEnumerable<T[]> Combinations<T>(this T[] values, int k)
{
    if (k < 0 || values.Length < k)
        yield break; // invalid parameters, no combinations possible

    // generate the initial combination indices
    var combIndices = new int[k];
    for (var i = 0; i < k; i++)
    {
        combIndices[i] = i;
    }

    while (true)
    {
        // return next combination
        var combination = new T[k];
        for (var i = 0; i < k; i++)
        {
            combination[i] = values[combIndices[i]];
        }
        yield return combination;

        // find first index to update
        var indexToUpdate = k - 1;
        while (indexToUpdate >= 0 && combIndices[indexToUpdate] >= values.Length - k + indexToUpdate)
        {
            indexToUpdate--;
        }

        if (indexToUpdate < 0)
            yield break; // done

        // update combination indices
        for (var combIndex = combIndices[indexToUpdate] + 1; indexToUpdate < k; indexToUpdate++, combIndex++)
        {
            combIndices[indexToUpdate] = combIndex;
        }
    }
}

टेस्ट कोड:

foreach (var combination in new[] {'a', 'b', 'c', 'd', 'e'}.Combinations(3))
{
    System.Console.WriteLine(String.Join(" ", combination));
}

आउटपुट:

a b c
a b d
a b e
a c d
a c e
a d e
b c d
b c e
b d e
c d e

यह आर्डर को सुरक्षित रखता है। मैं परिणाम सेट की अपेक्षा कर रहा हूँ c b aजिसमें यह भी शामिल नहीं है।
दिमित्री नेस्टरुक

कार्य सभी संयोजनों को उत्पन्न करना है जो n पर k को संतुष्ट करते हैं। द्विपद गुणांक इस सवाल का जवाब देता है कि n तत्वों के एक निश्चित सेट से k तत्वों के अनधिकृत उपसमुच्चय को चुनने के कितने तरीके हैं । इसलिए प्रस्तावित एल्गोरिथ्म वही करता है जो उसे करना चाहिए।
क्रिस्टोफ

6

https://gist.github.com/3118596

जावास्क्रिप्ट के लिए एक कार्यान्वयन है। यह किसी भी वस्तु की एक सरणी के k- संयोजन और सभी संयोजन प्राप्त करने के लिए कार्य करता है। उदाहरण:

k_combinations([1,2,3], 2)
-> [[1,2], [1,3], [2,3]]

combinations([1,2,3])
-> [[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]

6

यहाँ आपके पास C # में कोडित उस एल्गोरिथ्म का एक आलसी मूल्यांकित संस्करण है:

    static bool nextCombination(int[] num, int n, int k)
    {
        bool finished, changed;

        changed = finished = false;

        if (k > 0)
        {
            for (int i = k - 1; !finished && !changed; i--)
            {
                if (num[i] < (n - 1) - (k - 1) + i)
                {
                    num[i]++;
                    if (i < k - 1)
                    {
                        for (int j = i + 1; j < k; j++)
                        {
                            num[j] = num[j - 1] + 1;
                        }
                    }
                    changed = true;
                }
                finished = (i == 0);
            }
        }

        return changed;
    }

    static IEnumerable Combinations<T>(IEnumerable<T> elements, int k)
    {
        T[] elem = elements.ToArray();
        int size = elem.Length;

        if (k <= size)
        {
            int[] numbers = new int[k];
            for (int i = 0; i < k; i++)
            {
                numbers[i] = i;
            }

            do
            {
                yield return numbers.Select(n => elem[n]);
            }
            while (nextCombination(numbers, size, k));
        }
    }

और भाग का परीक्षण करें:

    static void Main(string[] args)
    {
        int k = 3;
        var t = new[] { "dog", "cat", "mouse", "zebra"};

        foreach (IEnumerable<string> i in Combinations(t, k))
        {
            Console.WriteLine(string.Join(",", i));
        }
    }

आशा है कि यह आपकी मदद करेगा!


6

मेरे पास एक क्रमिक एल्गोरिथ्म था जिसका उपयोग मैंने प्रोजेक्ट यूलर के लिए, अजगर में किया था:

def missing(miss,src):
    "Returns the list of items in src not present in miss"
    return [i for i in src if i not in miss]


def permutation_gen(n,l):
    "Generates all the permutations of n items of the l list"
    for i in l:
        if n<=1: yield [i]
        r = [i]
        for j in permutation_gen(n-1,missing([i],l)):  yield r+j

अगर

n<len(l) 

पुनरावृत्ति के बिना आपके पास सभी संयोजन होने चाहिए, क्या आपको इसकी आवश्यकता है?

यह एक जनरेटर है, इसलिए आप इसे इस तरह से उपयोग करते हैं:

for comb in permutation_gen(3,list("ABCDEFGH")):
    print comb 

5
Array.prototype.combs = function(num) {

    var str = this,
        length = str.length,
        of = Math.pow(2, length) - 1,
        out, combinations = [];

    while(of) {

        out = [];

        for(var i = 0, y; i < length; i++) {

            y = (1 << i);

            if(y & of && (y !== of))
                out.push(str[i]);

        }

        if (out.length >= num) {
           combinations.push(out);
        }

        of--;
    }

    return combinations;
}

5

क्लोजर संस्करण:

(defn comb [k l]
  (if (= 1 k) (map vector l)
      (apply concat
             (map-indexed
              #(map (fn [x] (conj x %2))
                    (comb (dec k) (drop (inc %1) l)))
              l))))

5

कहते हैं कि अक्षरों की आपकी सरणी इस तरह दिखती है: "ABCDEFGH"। आपके पास तीन सूचक हैं (i, j, k) जो दर्शाता है कि आप वर्तमान शब्द के लिए किन अक्षरों का उपयोग करने जा रहे हैं, आप इसके साथ शुरू करते हैं:

ABCDEFGH
^ ^ ^
IJK

पहले आप k भिन्न होते हैं, इसलिए अगला चरण ऐसा दिखता है:

ABCDEFGH
^ ^ ^
IJK

यदि आप अंत तक पहुँच गए हैं तो आप आगे बढ़ते हैं और फिर j और उसके बाद k फिर से बदलते हैं।

ABCDEFGH
^ ^ ^
IJK

ABCDEFGH
^ ^ ^
IJK

एक बार जब आप जी तक पहुँच गए तो आप भी मुझे अलग करना शुरू कर देंगे।

ABCDEFGH
  ^ ^ ^
  IJK

ABCDEFGH
  ^ ^ ^
  IJK
...
function initializePointers($cnt) {
    $pointers = [];

    for($i=0; $i<$cnt; $i++) {
        $pointers[] = $i;
    }

    return $pointers;     
}

function incrementPointers(&$pointers, &$arrLength) {
    for($i=0; $i<count($pointers); $i++) {
        $currentPointerIndex = count($pointers) - $i - 1;
        $currentPointer = $pointers[$currentPointerIndex];

        if($currentPointer < $arrLength - $i - 1) {
           ++$pointers[$currentPointerIndex];

           for($j=1; ($currentPointerIndex+$j)<count($pointers); $j++) {
                $pointers[$currentPointerIndex+$j] = $pointers[$currentPointerIndex]+$j;
           }

           return true;
        }
    }

    return false;
}

function getDataByPointers(&$arr, &$pointers) {
    $data = [];

    for($i=0; $i<count($pointers); $i++) {
        $data[] = $arr[$pointers[$i]];
    }

    return $data;
}

function getCombinations($arr, $cnt)
{
    $len = count($arr);
    $result = [];
    $pointers = initializePointers($cnt);

    do {
        $result[] = getDataByPointers($arr, $pointers);
    } while(incrementPointers($pointers, count($arr)));

    return $result;
}

$result = getCombinations([0, 1, 2, 3, 4, 5], 3);
print_r($result);

किसी भी आकार के संकेत के लिए https://stackoverflow.com/a/127898/2628125 , लेकिन अधिक सार पर आधारित है ।


यह कैसी भयावह भाषा है? दे घुमा के?
शिंज़ौ

1
php, लेकिन यहां भाषा कोई मायने नहीं रखती, एल्गोरिथ्म करता है
ओलेकेंड्रा कनिगा

मैं बहुत खुश हूं कि मैंने इस भाषा को सीखने से इनकार कर दिया। एक भाषा जहां इसके दुभाषिया / संकलक को चर पहचानने में मदद की जरूरत है 2018 में मौजूद नहीं होना चाहिए।
शिंजौ

4

सभी ने कहा और यहाँ किया गया है कि उसके लिए O'caml कोड आता है। एल्गोरिदम कोड से स्पष्ट है ..

let combi n lst =
    let rec comb l c =
        if( List.length c = n) then [c] else
        match l with
        [] -> []
        | (h::t) -> (combi t (h::c))@(combi t c)
    in
        combi lst []
;;

4

यहां एक विधि है जो आपको यादृच्छिक लंबाई स्ट्रिंग से निर्दिष्ट आकार के सभी संयोजन प्रदान करती है। क्विनमार्स के समाधान के समान है, लेकिन विभिन्न इनपुट और के लिए काम करता है।

कोड को चारों ओर से लपेटने के लिए परिवर्तित किया जा सकता है, अर्थात इनपुट 'abcd' wk = 3 से 'dab'।

public void run(String data, int howMany){
    choose(data, howMany, new StringBuffer(), 0);
}


//n choose k
private void choose(String data, int k, StringBuffer result, int startIndex){
    if (result.length()==k){
        System.out.println(result.toString());
        return;
    }

    for (int i=startIndex; i<data.length(); i++){
        result.append(data.charAt(i));
        choose(data,k,result, i+1);
        result.setLength(result.length()-1);
    }
}

"एब्सडे" के लिए आउटपुट:

abc abd abe acd ace ade bcd bce bde cde


3

मैंने इसके लिए SQL Server 2005 में एक समाधान बनाया, और इसे अपनी वेबसाइट पर पोस्ट किया: http://www.jessemclain.com/downloads/code/sql/fn_GetMChooseNCombos.sql.htm

उपयोग दिखाने के लिए यहां एक उदाहरण दिया गया है:

SELECT * FROM dbo.fn_GetMChooseNCombos('ABCD', 2, '')

परिणाम:

Word
----
AB
AC
AD
BC
BD
CD

(6 row(s) affected)

3

यहाँ C ++ में मेरा प्रस्ताव है

मैं itter प्रकार पर थोड़ा प्रतिबंध लगाने की कोशिश के रूप में मैं कर सकता है तो यह समाधान सिर्फ आगे चलनेवाला मानता है, और यह एक const_iterator हो सकता है। यह किसी भी मानक कंटेनर के साथ काम करना चाहिए। ऐसे मामलों में जहां तर्क से कोई मतलब नहीं है कि यह std :: अमान्य_argumnent है

#include <vector>
#include <stdexcept>

template <typename Fci> // Fci - forward const iterator
std::vector<std::vector<Fci> >
enumerate_combinations(Fci begin, Fci end, unsigned int combination_size)
{
    if(begin == end && combination_size > 0u)
        throw std::invalid_argument("empty set and positive combination size!");
    std::vector<std::vector<Fci> > result; // empty set of combinations
    if(combination_size == 0u) return result; // there is exactly one combination of
                                              // size 0 - emty set
    std::vector<Fci> current_combination;
    current_combination.reserve(combination_size + 1u); // I reserve one aditional slot
                                                        // in my vector to store
                                                        // the end sentinel there.
                                                        // The code is cleaner thanks to that
    for(unsigned int i = 0u; i < combination_size && begin != end; ++i, ++begin)
    {
        current_combination.push_back(begin); // Construction of the first combination
    }
    // Since I assume the itarators support only incrementing, I have to iterate over
    // the set to get its size, which is expensive. Here I had to itrate anyway to  
    // produce the first cobination, so I use the loop to also check the size.
    if(current_combination.size() < combination_size)
        throw std::invalid_argument("combination size > set size!");
    result.push_back(current_combination); // Store the first combination in the results set
    current_combination.push_back(end); // Here I add mentioned earlier sentinel to
                                        // simplyfy rest of the code. If I did it 
                                        // earlier, previous statement would get ugly.
    while(true)
    {
        unsigned int i = combination_size;
        Fci tmp;                            // Thanks to the sentinel I can find first
        do                                  // iterator to change, simply by scaning
        {                                   // from right to left and looking for the
            tmp = current_combination[--i]; // first "bubble". The fact, that it's 
            ++tmp;                          // a forward iterator makes it ugly but I
        }                                   // can't help it.
        while(i > 0u && tmp == current_combination[i + 1u]);

        // Here is probably my most obfuscated expression.
        // Loop above looks for a "bubble". If there is no "bubble", that means, that
        // current_combination is the last combination, Expression in the if statement
        // below evaluates to true and the function exits returning result.
        // If the "bubble" is found however, the ststement below has a sideeffect of 
        // incrementing the first iterator to the left of the "bubble".
        if(++current_combination[i] == current_combination[i + 1u])
            return result;
        // Rest of the code sets posiotons of the rest of the iterstors
        // (if there are any), that are to the right of the incremented one,
        // to form next combination

        while(++i < combination_size)
        {
            current_combination[i] = current_combination[i - 1u];
            ++current_combination[i];
        }
        // Below is the ugly side of using the sentinel. Well it had to haave some 
        // disadvantage. Try without it.
        result.push_back(std::vector<Fci>(current_combination.begin(),
                                          current_combination.end() - 1));
    }
}

3

यहां एक कोड है जिसे मैंने हाल ही में जावा में लिखा था, जो "आउट" तत्वों से "संख्या" तत्वों के सभी संयोजन की गणना और रिटर्न करता है।

// author: Sourabh Bhat (heySourabh@gmail.com)

public class Testing
{
    public static void main(String[] args)
    {

// Test case num = 5, outOf = 8.

        int num = 5;
        int outOf = 8;
        int[][] combinations = getCombinations(num, outOf);
        for (int i = 0; i < combinations.length; i++)
        {
            for (int j = 0; j < combinations[i].length; j++)
            {
                System.out.print(combinations[i][j] + " ");
            }
            System.out.println();
        }
    }

    private static int[][] getCombinations(int num, int outOf)
    {
        int possibilities = get_nCr(outOf, num);
        int[][] combinations = new int[possibilities][num];
        int arrayPointer = 0;

        int[] counter = new int[num];

        for (int i = 0; i < num; i++)
        {
            counter[i] = i;
        }
        breakLoop: while (true)
        {
            // Initializing part
            for (int i = 1; i < num; i++)
            {
                if (counter[i] >= outOf - (num - 1 - i))
                    counter[i] = counter[i - 1] + 1;
            }

            // Testing part
            for (int i = 0; i < num; i++)
            {
                if (counter[i] < outOf)
                {
                    continue;
                } else
                {
                    break breakLoop;
                }
            }

            // Innermost part
            combinations[arrayPointer] = counter.clone();
            arrayPointer++;

            // Incrementing part
            counter[num - 1]++;
            for (int i = num - 1; i >= 1; i--)
            {
                if (counter[i] >= outOf - (num - 1 - i))
                    counter[i - 1]++;
            }
        }

        return combinations;
    }

    private static int get_nCr(int n, int r)
    {
        if(r > n)
        {
            throw new ArithmeticException("r is greater then n");
        }
        long numerator = 1;
        long denominator = 1;
        for (int i = n; i >= r + 1; i--)
        {
            numerator *= i;
        }
        for (int i = 2; i <= n - r; i++)
        {
            denominator *= i;
        }

        return (int) (numerator / denominator);
    }
}

3

एक संक्षिप्त समाधान

Array.prototype.combine=function combine(k){    
    var toCombine=this;
    var last;
    function combi(n,comb){             
        var combs=[];
        for ( var x=0,y=comb.length;x<y;x++){
            for ( var l=0,m=toCombine.length;l<m;l++){      
                combs.push(comb[x]+toCombine[l]);           
            }
        }
        if (n<k-1){
            n++;
            combi(n,combs);
        } else{last=combs;}
    }
    combi(1,toCombine);
    return last;
}
// Example:
// var toCombine=['a','b','c'];
// var results=toCombine.combine(4);

3

कलन विधि:

  • 1 से 2 ^ n तक की गणना करें।
  • प्रत्येक अंक को अपने बाइनरी प्रतिनिधित्व में बदलें।
  • स्थिति के आधार पर अपने सेट के तत्वों के लिए प्रत्येक 'बिट' पर अनुवाद करें।

C # में:

void Main()
{
    var set = new [] {"A", "B", "C", "D" }; //, "E", "F", "G", "H", "I", "J" };

    var kElement = 2;

    for(var i = 1; i < Math.Pow(2, set.Length); i++) {
        var result = Convert.ToString(i, 2).PadLeft(set.Length, '0');
        var cnt = Regex.Matches(Regex.Escape(result),  "1").Count; 
        if (cnt == kElement) {
            for(int j = 0; j < set.Length; j++)
                if ( Char.GetNumericValue(result[j]) == 1)
                    Console.Write(set[j]);
            Console.WriteLine();
        }
    }
}

यह काम क्यों करता है?

एन-तत्व सेट और एन-बिट अनुक्रमों के सबसेट के बीच एक आपत्ति है।

इसका मतलब है कि हम यह पता लगा सकते हैं कि अनुक्रमों की गिनती के द्वारा कितने सबसेट हैं।

उदाहरण के लिए, नीचे दिए गए चार तत्व को {0,1} X {0, 1} X {0, 1} X {0, 1} (या 2 ^ 4) विभिन्न अनुक्रमों द्वारा दर्शाया जा सकता है।

इसलिए - हमें सभी संयोजनों को खोजने के लिए 1 से 2 ^ n तक की गणना करनी है। (हम खाली सेट की उपेक्षा करते हैं।) अगला, अंकों को उनके द्विआधारी प्रतिनिधित्व में अनुवाद करें। फिर अपने सेट के तत्वों को 'ऑन' बिट्स के लिए चुनें।

यदि आप केवल k तत्व परिणाम चाहते हैं, तो केवल तभी प्रिंट करें जब k बिट्स 'ऑन' हों।

(यदि आप k लंबाई उपसमुच्चय के बजाय सभी सबसेट चाहते हैं, तो cnt / kElement भाग को हटा दें।)

(प्रमाण के लिए, कंप्यूटर साइंस, लेहमन एट अल, सेक्शन 11.2.2 के लिए MIT मुक्त शोध गणित देखें। https://ocw.mit.edu/courses/electrical-engineering-and-computer-science-6-042j-mathematics- कंप्यूटर-विज्ञान-पतन -२०१० / ​​रीडिंग / के लिए )


3

छोटे अजगर कोड, उपज सूचकांक पदों

def yield_combos(n,k):
    # n is set size, k is combo size

    i = 0
    a = [0]*k

    while i > -1:
        for j in range(i+1, k):
            a[j] = a[j-1]+1
        i=j
        yield a
        while a[i] == i + n - k:
            i -= 1
        a[i] += 1

2

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

  1. किसी फ़ाइल को किसी भी N चुनने के लिए एक अच्छे प्रारूप में सभी K-indexs को आउटपुट करता है। K-indexes को अधिक वर्णनात्मक तारों या अक्षरों के साथ प्रतिस्थापित किया जा सकता है। यह विधि इस प्रकार की समस्या को काफी तुच्छ हल करती है।

  2. K- अनुक्रमणिका को सॉर्ट किए गए द्विपद गुणांक तालिका में एक प्रविष्टि के उचित सूचकांक में परिवर्तित करता है। यह तकनीक पुरानी प्रकाशित तकनीकों की तुलना में बहुत तेज है जो पुनरावृत्ति पर निर्भर करती है। यह पास्कल के त्रिभुज में निहित गणितीय संपत्ति का उपयोग करके ऐसा करता है। मेरा पेपर इस बारे में बात करता है। मेरा मानना ​​है कि मैं इस तकनीक को खोजने और प्रकाशित करने वाला पहला व्यक्ति हूं, लेकिन मैं गलत हो सकता हूं।

  3. अनुक्रमणित द्विपद गुणांक तालिका में अनुक्रमणिका को संबंधित K- अनुक्रमणिका में कनवर्ट करता है।

  4. द्विपदीय गुणांक की गणना करने के लिए मार्क डोमिनस विधि का उपयोग करता है , जो अतिप्रवाह की संभावना कम है और बड़ी संख्या के साथ काम करता है।

  5. वर्ग .NET C # में लिखा गया है और जेनेरिक सूची का उपयोग करके समस्या से संबंधित वस्तुओं (यदि कोई हो) का प्रबंधन करने का एक तरीका प्रदान करता है। इस वर्ग का निर्माता InitTable नामक एक बूल मान लेता है कि जब सत्य वस्तुओं को प्रबंधित करने के लिए धारण करने के लिए एक सामान्य सूची बनाएगा। यदि यह मान गलत है, तो यह तालिका नहीं बनाएगा। उपरोक्त 4 विधियों को करने के लिए तालिका बनाने की आवश्यकता नहीं है। तालिका तक पहुँचने के लिए सहायक विधियाँ प्रदान की जाती हैं।

  6. एक संबद्ध परीक्षण वर्ग है जो दिखाता है कि कक्षा और उसके तरीकों का उपयोग कैसे किया जाए। यह बड़े पैमाने पर 2 मामलों के साथ परीक्षण किया गया है और कोई ज्ञात बग नहीं हैं।

इस वर्ग के बारे में पढ़ने के लिए और कोड डाउनलोड करने के लिए, द्विपद कोइफ़िसेन्ट को टैबलाइज़ करना देखें

इस वर्ग को C ++ में बदलना कठिन नहीं होना चाहिए।


इसे "मार्क डोमिनस विधि" कहना वास्तव में सही नहीं है, क्योंकि जैसा कि मैंने उल्लेख किया है कि यह कम से कम 850 साल पुराना है, और ऐसा सोचना मुश्किल नहीं है। इसे लीलावती विधि क्यों नहीं कहते ?
MJD
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.