2010-01-25 21 views
9

मैं अपने सिर को खरोंच कर रहा हूं और यह मुझे खा रहा है। मुझे पता है कि यह जटिल नहीं है। मेरे पास कई आइटम हैं, यह संख्या बराबर या तीन से अधिक हो सकती है। तो मुझे उन वस्तुओं के समूह के संभावित संयोजन को निर्धारित करने की आवश्यकता है जो कुल को पूरा करेंगे। केवल एक ही प्रतिबंध यह है कि समूहों में तीन या अधिक वस्तुएं होनी चाहिए, जो सात वस्तुओं (लेकिन सहित) से अधिक नहीं होनी चाहिए।आइटम के संभावित समूहों को निर्धारित करने के लिए एल्गोरिदम

उदाहरण के लिए:

अगर मैं 7 आइटम नहीं हैं, तो मैं इन संभव समूह बना सकते हैं:

  • 1 7 वस्तुओं के समूह।
  • 4 आइटमों का 1 समूह और 3 आइटमों का 1 समूह।

अगर मैं 12 आइटम नहीं हैं, मैं इन संभव समूह बना सकते हैं:

  • 4 3 आइटम के समूहों।
  • 4 आइटम के 3 समूह।
  • 6 आइटम के 2 समूह।
  • 7 आइटमों का 1 समूह + 5 आइटमों का 1 समूह।
  • 6 आइटमों के 3 और 1 समूह के 2 समूह।
  • 3 का 1 समूह, 4 समूह के 1 समूह और पांच वस्तुओं के 1 समूह।
  • ...

मैं प्रत्यावर्तन के बारे में सोचा और कलन विधि को लागू करने शुरू कर दिया। यह स्पष्ट रूप से काम नहीं कर रहा है। मैं रिकर्सन पर चूसना। बहुत।

//Instance Fields 
public List<ArrayList<String>> options; 

//Method that will generate the options. The different options are 
//stored in a list of "option". An individual option will store a list of 
//strings with the individual groups. 
public void generateOptions(int items, ArrayList<String> currentOption){ 

    //If the current option is null, then create a new option. 
    if(currentOption == null){ 
     currentOption = new ArrayList<String>(); 
    } 
    if(items < 3){ 
     //If the number of items is less than three then it doesn't comply with the 
     //requirements (teams should be more or equal than three. 
     currentOption.add("1 group of "+items+" items"); 
     options.add(currentOption); 
    } 
    else{ 
     //I can make groups of 3,4,5,6 and 7 items. 
     for(int i = 3;i<=7;i++){ 
      if(items%i == 0){ 
       // If the number of items is divisible per the current number, 
       // then a possible option could be items/i groups of i items. 
       // Example: Items = 9. A possible option is 3 groups of 3 items. 
       currentOption.add(items/i +" groups of "+ i+" items"); 
       options.add(currentOption); 
      } 
      else{ 
       // If the number of items - the current number is equal or greater than 
       // three, then a possible option could be a group of i items 
       // and then I'll have items-i items to separate in other groups. 
       if(items - i >=3){ 
        currentOption.add("1 group of "+i+" items"); 
        generateOptions(items-i,currentOption); 
       } 
      } 
     } 
    } 
} 

आपकी मदद के लिए धन्यवाद !!!

उत्तर

4

यहाँ एक एल्गोरिथ्म (C++ में व्यक्त) समस्या, addends कि प्रत्येक में दिखाई दे सकते पर मनमाने ढंग से ऊपरी और निचले सीमा के साथ की एक अधिक सामान्य संस्करण का समाधान करने के लिए विभाजन:

#include <iostream> 
#include <vector> 

using namespace std; 

typedef vector<int> Partition; 
typedef vector<Partition> Partition_list; 

// Count and return all partitions of an integer N using only 
// addends between min and max inclusive. 

int p(int min, int max, int n, Partition_list &v) 
{ 
    if (min > max) return 0; 
    if (min > n) return 0;  
    if (min == n) { 
     Partition vtemp(1,min); 
     v.push_back(vtemp); 
     return 1; 
    } 
    else { 
    Partition_list part1,part2; 
    int p1 = p(min+1,max,n,part1); 
    int p2 = p(min,max,n-min,part2); 
    v.insert(v.end(),part1.begin(),part1.end()); 
    for(int i=0; i < p2; i++) 
    { 
     part2[i].push_back(min); 
    } 
    v.insert(v.end(),part2.begin(),part2.end()); 
    return p1+p2; 
    } 
} 

void print_partition(Partition &p) 
{ 
    for(int i=0; i < p.size(); i++) { 
     cout << p[i] << ' '; 
    } 
    cout << "\n"; 
} 

void print_partition_list(Partition_list &pl) 
{ 
    for(int i = 0; i < pl.size(); i++) { 
     print_partition(pl[i]); 
    } 
} 

int main(int argc, char **argv) 
{ 
    Partition_list v_master; 

    int n = atoi(argv[1]); 
    int min = atoi(argv[2]); 
    int max = atoi(argv[3]); 
    int count = p(min,max,n,v_master); 
    cout << count << " partitions of " << n << " with min " << min ; 
    cout << " and max " << max << ":\n" ; 
    print_partition_list(v_master); 
} 

और कुछ नमूना उत्पादन:

$ ./partitions 12 3 7    
6 partitions of 12 with min 3 and max 7: 
6 6 
7 5 
4 4 4 
5 4 3 
6 3 3 
3 3 3 3 
$ ./partitions 50 10 20    
38 partitions of 50 with min 10 and max 20: 
17 17 16 
18 16 16 
18 17 15 
19 16 15 
20 15 15 
18 18 14 
19 17 14 
20 16 14 
19 18 13 
20 17 13 
19 19 12 
20 18 12 
13 13 12 12 
14 12 12 12 
20 19 11 
13 13 13 11 
14 13 12 11 
15 12 12 11 
14 14 11 11 
15 13 11 11 
16 12 11 11 
17 11 11 11 
20 20 10 
14 13 13 10 
14 14 12 10 
15 13 12 10 
16 12 12 10 
15 14 11 10 
16 13 11 10 
17 12 11 10 
18 11 11 10 
15 15 10 10 
16 14 10 10 
17 13 10 10 
18 12 10 10 
19 11 10 10 
20 10 10 10 
10 10 10 10 10 
+0

यह जो मैं देख रहा हूं उससे बहुत करीब है। मैं यह देखने के लिए जावा में इसे बदलने की कोशिश कर रहा हूं कि यह कैसे काम करता है। धन्यवाद। – miguelrios

1

इस n के partitions जो सेट से केवल पूर्णांकों शामिल [3,7]

नियमित विभाजन समस्या (जहां तत्वों किसी भी धनात्मक पूर्णांक हो सकता है) के लिए इसी तरह की संख्या होगी:

http://www.research.att.com/~njas/sequences/A000041

मुझे मौजूदा संख्या अनुक्रम नहीं दिखाई देता है जो इस बाधा से बिल्कुल मेल खाता है, लेकिन आप इस तरह के समूहों को गिन सकते हैं (पायथन में)। यह इस मामले में एक मनमाने ढंग से रेंज ([3,7] ले सकता है) और सभी ए, बी, सी, डी, ई (3 * ए + 4 * बी +5 * सी +6 * डी + 7 * ई) गिनें अनुक्रम जो एन को योग करते हैं।

import sys 

# All partitions for a particular n: 

def groups(n, base, minBase, sum, sets, group = []): 
    c = 0; i = (n - sum)/base 
    while i >= 0: 
    s = sum + base * i 
    if s == n: 
     sets.append(group + [i]); 
     c = c + 1 
    elif s < n and base > minBase: 
     c = c + groups(n, base - 1, minBase, s, sets, (group + [i])) 
    i = i - 1 
    return c 

# Partitions for each n in [1,maxNum] 

def run(maxNum): 
    for i in xrange(1, maxNum + 1): 
    sets = []; maxBase = 7; minBase = 3 
    n = groups(i, maxBase, minBase, 0, sets) 
    print ' %d has %d groups:\n' % (i, n) 
    for g in sets: 
     x = len(g) - 1 
     sys.stdout.write('  ') 
     while x >= 0: 
     if g[x] > 0: 
      if x < len(g) - 1: sys.stdout.write(' + ') 
      sys.stdout.write('(%d * %d)' % (maxBase - x, g[x])) 
     x = x - 1 
     print '' 
    if len(sets): print '' 

run(40) 

आप होगा:

1 has 0 groups: 

2 has 0 groups: 

3 has 1 groups: 

    (3 * 1) 

4 has 1 groups: 

    (4 * 1) 

5 has 1 groups: 

    (5 * 1) 

6 has 2 groups: 

    (6 * 1) 
    (3 * 2) 

7 has 2 groups: 

    (7 * 1) 
    (3 * 1) + (4 * 1) 

8 has 2 groups: 

    (3 * 1) + (5 * 1) 
    (4 * 2) 

9 has 3 groups: 

    (3 * 1) + (6 * 1) 
    (4 * 1) + (5 * 1) 
    (3 * 3) 

10 has 4 groups: 

    (3 * 1) + (7 * 1) 
    (4 * 1) + (6 * 1) 
    (5 * 2) 
    (3 * 2) + (4 * 1) 

11 has 4 groups: 

    (4 * 1) + (7 * 1) 
    (5 * 1) + (6 * 1) 
    (3 * 2) + (5 * 1) 
    (3 * 1) + (4 * 2) 

12 has 6 groups: 

    (5 * 1) + (7 * 1) 
    (6 * 2) 
    (3 * 2) + (6 * 1) 
    (3 * 1) + (4 * 1) + (5 * 1) 
    (4 * 3) 
    (3 * 4) 

13 has 6 groups: 

    (6 * 1) + (7 * 1) 
    (3 * 2) + (7 * 1) 
    (3 * 1) + (4 * 1) + (6 * 1) 
    (3 * 1) + (5 * 2) 
    (4 * 2) + (5 * 1) 
    (3 * 3) + (4 * 1) 

14 has 7 groups: 

    (7 * 2) 
    (3 * 1) + (4 * 1) + (7 * 1) 
    (3 * 1) + (5 * 1) + (6 * 1) 
    (4 * 2) + (6 * 1) 
    (4 * 1) + (5 * 2) 
    (3 * 3) + (5 * 1) 
    (3 * 2) + (4 * 2) 

15 has 9 groups: 

    (3 * 1) + (5 * 1) + (7 * 1) 
    (4 * 2) + (7 * 1) 
    (3 * 1) + (6 * 2) 
    (4 * 1) + (5 * 1) + (6 * 1) 
    (3 * 3) + (6 * 1) 
    (5 * 3) 
    (3 * 2) + (4 * 1) + (5 * 1) 
    (3 * 1) + (4 * 3) 
    (3 * 5) 

या @ कि्लिटस के उत्कृष्ट समाधान

3

यह प्रत्यावर्तन के साथ किया जा सकता है। आप यह नहीं कहते कि आप सिर्फ संभावनाओं या वास्तविक संभावनाओं की संख्या चाहते हैं।

एक चीज जो आप करना चाहते हैं वह पुनरावृत्ति से बचने का अर्थ है 4 और 3 को 3 और 4 के रूप में भी गिनती नहीं है। ऐसा करने का एक तरीका गैर-अवरोही समूह आकारों के अनुक्रम बनाना है।

root 
+- 12 
+- 9 
| +- 3 
+- 8 
| +- 4 
+- 7 
| +- 5 
+- 6 
| +- 6 
| +- 3 
|  +- 3 
+- 5 
| +- 4 
|  +- 3 
+- 4 
| +- 4 
|  +- 4 
+- 3 
    +- 3 
     +- 3 
     +- 3 

तो फिर तुम बस पत्र-गांठ गिनती संयोजनों की संख्या को खोजने के लिए:

शायद इसके लिए सबसे अच्छा डेटा संरचना एक पेड़ है। वास्तविक संयोजन खोजने के लिए आप बस पेड़ पर चलते हैं।

इस तरह के एक पेड़ के निर्माण के लिए एल्गोरिथ्म कुछ इस तरह चला जाता है:

  • समारोह buildTree (पूर्णांक आकार, इंट minSize, ट्री रूट) size से minSize करने के लिए नीचे
  • गणना i;
  • मूल्य i के साथ वर्तमान नोड का एक बच्चा बनाएं;
  • i को minSize से प्रत्येक j कि i
    • के बराबर या उससे कम है के लिए मूल्य का एक नया बच्चा बनाएं j
    • कॉल `buildTree (जे, minSize, नए नोड)

या उसके बहुत करीब कुछ।

+0

जंग [http: // जंग। sourceforge.net/doc/api/edu/uci/ics/jung/graph/Tree.html] में एक वृक्ष कार्यान्वयन है जो मदद कर सकता है। – harschware

+0

मुझे लगता है कि मैं इसे समझता हूं, लेकिन इस डेटा संरचना में 6 और 6 के 2 समूह कहां प्रदर्शित होते हैं? क्या 6 शाखा 6 से 6 और 6 से 3 से 3 तक होनी चाहिए, या क्या मैं इसे गलत समझ रहा हूं? –

+0

इसके अलावा, हर्स्चवेयर के जंगल यूआरएल का पिछला भाग है], ऐसा लगता है कि यह http://jung.sourceforge.net/doc/api/edu/uci/ics/jung/graph/Tree.html –

1

एक पेड़ इसके बारे में सोचने का सबसे अच्छा तरीका है, लेकिन आप एक पेड़ बनाने के बिना एक बनाने के लिए रिकर्सन का उपयोग कर सकते हैं। आप मूल के रूप में रूट के बारे में सोच सकते हैं। आकार 3-7 के समूहों का उपयोग करके, आपको उन समूहों के कुछ संयोजनों को ढूंढना होगा जो आपके कुल तक पहुंचते हैं।

आप 7 के समूह, 7 के 1 समूह, 7 के 2 समूह इत्यादि का उपयोग कर सकते हैं। इनमें से प्रत्येक मान के लिए, आप 6 के समूह, 6 के 1 समूह, आदि का उपयोग कर सकते हैं। पेड़ का प्रतिनिधित्व करेगा कि कितने 7 का इस्तेमाल किया गया था। दूसरा स्तर यह है कि कितने 6 का उपयोग किया गया था, आदि। जब आप एक्स 7 का उपयोग करते हैं, तो आपको यह पता लगाना होगा कि 6, 5, 4, और 3 के कितने संयोजन आप योग (योग -7 * 7) तक जोड़ सकते हैं। , और प्रत्येक निचले स्तर (रिकर्सिव कॉल) के लिए भी।

आपके पेड़ में हमेशा 5 स्तर होंगे।

पेड़ बनाने के लिए रिकर्सन का उपयोग करके, यहां एक छोटा पायथन कोड नमूना है (पेड़ को छूने का कोई प्रयास नहीं है, यह पूरी चीज का पता लगाएगा)।

MIN = 3 
MAX = 7 

def findComb(remaining, start, path): 
    times = remaining/start 

    if start == MIN: 
     if remaining % MIN == 0: 
      print "%s, %d %d's" % (path[1:], times, start) 
     return 

    for i in range(0, times+1): 
     findComb(remaining- (i*start), start-1, "%s, %d %d's" % (path, i, start)) 


findComb(12, MAX, "") 

यह आउटपुट:

0 7's, 0 6's, 0 5's, 0 4's, 4 3's 
0 7's, 0 6's, 0 5's, 3 4's, 0 3's 
0 7's, 0 6's, 1 5's, 1 4's, 1 3's 
0 7's, 1 6's, 0 5's, 0 4's, 2 3's 
0 7's, 2 6's, 0 5's, 0 4's, 0 3's 
1 7's, 0 6's, 1 5's, 0 4's, 0 3's 
0

स्यूडोकोड में:

List<String> results; 

void YourAnswer(int n) { 
    GeneratePossiblities("", [3, 4, 5, 6, 7], n); 
} 

void GeneratePossibilities(String partialResult, List<int> buildingBlocks, int n) { 
    if (n == 0) { 
     // We have a solution 
     results.Add(partialResult); 
    } else if (buildingBlocks.IsEmpty()) { 
     // Dead-end: there is no solution that starts with the partial result we have and contains only the remaining building blocks 
     return; 
    } else { 
     int first = buildingBlocks.First(); 
     buildingBlocks.PopFirst(); 
     for (int i = 0, i < n/first; i++) { 
      GeneratePossibilities(partialResult + " " + i + "groups of " + first, 
           buildingBlocks, 
           n - i * first); 
     } 
    } 
} 

पहले दो मामलों सुंदर सीधी-सपाट हैं।तीसरा, आप समझते हैं (उदाहरण के लिए) आकार 3 के कितने समूह हैं - यह 0 और एन/3 के बीच कोई संख्या हो सकती है, और फिर [4, 5, 6, 7] इत्यादि के साथ फ़ंक्शन को पुन: क्रमबद्ध कर सकती है।

0

जो आप वर्णन कर रहे हैं वह partition function का एक सामान्य सामान्य संस्करण है।

एल्गोरिदम पहले ही दिया हास्यास्पद जटिल हैं, यहाँ एक सरल एक है (छद्म कोड में, मैं यह आप पर छोड़ते जावा :) में अनुवाद करना होगा)

p(min, n): 
    if min > n: return 0 
    if min = n: return 1 
    return p(min+1, n) + p(min, n-min) 
+0

यह मुझे केवल विभाजन की संख्या देगा। मुझे खुद विभाजनों की भी आवश्यकता है। धन्यवाद! – miguelrios

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