2009-07-16 11 views
7

कुछ पृष्ठभूमि के साथ अनोखा क्रमपरिवर्तन। ऐसा करने के लिए, मुझे सर्वोत्तम संभावनाओं को जानने के लिए सभी संभावनाओं को उत्पन्न और मूल्यांकन करने की आवश्यकता है। चूंकि मूल्यांकन में वास्तव में कुछ समय लगता है, इसलिए मैं जितनी कम संभव समाधान उत्पन्न करना पसंद करूंगा जो पूरी तरह से मेरी खोज स्थान को कवर करे। इसके अलावा, मैं जितना अधिक तत्व कर सकता हूं, उतना बेहतर होगा। किसी भी संख्या के लिए के सामान्य रूप से के हैं! क्रमपरिवर्तन, और उन्हें उत्पन्न करना ~ 10 से अधिक संख्याओं के लिए कठिन होगा।कोई मिरर या परिपत्र repetitions

रियल समस्या: खोज अंतरिक्ष दो तत्वों के सभी क्रमपरिवर्तन (एन बार EL1 और एम बार el2, जहां कश्मीर = एम + एन), इन प्रतिबंधों के साथ शामिल करना चाहिए:

  1. वे अद्वितीय होना है (यानी मैं केवल एक बार [एबीबीबी] चाहता हूं)
  2. मुझे किसी भी क्रमपरिवर्तन के विपरीत की आवश्यकता नहीं है (यानी यदि मेरे पास [एएबी] है, तो मुझे [baa] की भी आवश्यकता नहीं है)
  3. मैं परमिट मानता हूं परिपत्र, इसलिए [AAB] = [ए.बी.ए.] = [भेड़]

यदि मैं ऐसा करने में सक्षम हूं, तो संभावनाओं की संख्या में काफी कमी आएगी। चूंकि के आदर्श आदर्श रूप से बड़ा होगा, इसलिए सभी क्रमिक क्रम उत्पन्न करने के लिए संभव नहीं है और फिर इन मानदंडों के अनुसार उन्हें फ़िल्टर करें। मैंने पहले ही प्रतिबंध लगा दिया है (नीचे देखें) और यह मैटलैब के सामान्य क्रमपरिवर्तन फ़ंक्शन (परमिट) के लिए के ^/एन! एम! के लिए 2^के से संख्या को वापस कर देता है, जो एक बड़ी जीत है। दूसरा प्रतिबंध केवल आधे (सर्वोत्तम मामले में) की संभावनाओं को कम करेगा, लेकिन मुझे लगता है कि तीसरा भी संभावनाओं की संख्या में कटौती करने में सक्षम होना चाहिए।

किसी को भी जानता है कि यह कैसे करना है, और अधिमानतः भी गणना करने के लिए कैसे कैसे कई संभावनाएं नहीं होगा, तो है कि मुझे बहुत मदद मिलेगी! मैं एक स्पष्टीकरण पसंद करूंगा, लेकिन कोड भी ठीक है (मैं सी जैसी भाषाओं, जावा (स्क्रिप्ट), पायथन, रूबी, लिस्प/स्कीम पढ़ सकता हूं)।


रुचि के लिए:

function genPossibilities(n, m, e1, e2) 
    if n == 0 
     return array of m e2's 
    else 
     possibilities = genPossibilities(n-1, m, e1, e2) 
     for every possibility: 
      gain = number of new possibilities we'll get for this smaller possibility* 
      for i in max(0,(m+n-gain)) 
       if possibility(i) is not e1 
        add possiblity with e1 inserted in position i 
     return new possibilities 
  • आप N-1 और एम के लिए सभी क्रमपरिवर्तन है, तो आप कर सकते हैं: यहाँ केवल अद्वितीय क्रमपरिवर्तन मैं अब तक है कि प्राप्त करने के लिए एल्गोरिथ्म है उनको ई 1 डालने से एन और एम के लिए क्रमपरिवर्तन खोजने के लिए उनका उपयोग करें। हालांकि आप बस हर जगह सम्मिलित नहीं कर सकते हैं, क्योंकि तब आपको डुप्लिकेट मिलेंगे। मुझे नहीं पता कि यह क्यों काम करता है, लेकिन आप पुराने संभावनाओं से उत्पन्न होने वाली नई संभावनाओं की संख्या की गणना कर सकते हैं (मैं इसे 'लाभ' कहता हूं)। यह संख्या पहले पुराने क्रमपरिवर्तन के लिए एम + 1 से शुरू होती है और प्रत्येक पुराने क्रमपरिवर्तन के लिए एक से कम हो जाती है जब तक कि यह शून्य न हो जाए, जिस बिंदु पर यह एम पर वापस आ जाता है, आदि (केवल एम> = एन) काम करता है। तो यदि आप एन = 3 और एम = 3 के लिए क्रमपरिवर्तन की गणना करना चाहते हैं और आपके पास एन = 2 और एम = 3 के लिए 10 क्रमपरिवर्तन हैं, तो उनके लाभ [4 3 2 1 3 2 1 2 1 1] होंगे। इस लाभ को क्रमपरिवर्तन की लंबाई से घटाएं और आपको वह अनुक्रमणिका मिलती है जिस पर आप डुप्लिकेट किए बिना नए तत्व डालने शुरू कर सकते हैं।

उत्तर

2

आप जो हैं उसके बाद 2-आरी कंगन का सबसेट है (सबसेट को वर्ण ए के चरित्र ए और एम के एम द्वारा परिभाषित किया गया है)। का सेट सभी कंगन ए और बी के भिन्न होने की अनुमति देता है।

निम्न कोड आपके द्वारा अनुक्रमित किए गए अनुक्रमों को प्रिंट करता है, और यह क्रमिक क्रम में और निरंतर अमूर्त समय में करता है। यह this paper by Sawada में सामान्य एल्गोरिदम पर आधारित है - यह कैसे काम करता है इसकी व्याख्या के लिए, उस पेपर को देखें।

#include <stdlib.h> 
#include <stdio.h> 

static int *a; 
static int n; 

void print_bracelet(int n, int a[]) 
{ 
    int i; 

    printf("["); 
    for (i = 0; i < n; i++) 
     printf(" %c", 'a' + a[i]); 
    printf(" ]\n"); 
} 

int check_rev(int t, int i) 
{ 
    int j; 

    for (j = i+1; j <= (t + 1)/2; j++) 
    { 
     if (a[j] < a[t-j+1]) 
      return 0; 
     if (a[j] > a[t-j+1]) 
      return -1; 
    } 

    return 1; 
} 

void gen_bracelets(int n_a, int n_b, int t, int p, int r, int u, int v, int rs) 
{ 
    if (2 * (t - 1) > (n + r)) 
    { 
     if (a[t-1] > a[n-t+2+r]) 
      rs = 0; 
     else if (a[t-1] < a[n-t+2+r]) 
      rs = 1; 
    } 
    if (t > n) 
    { 
     if (!rs && (n % p) == 0) 
      print_bracelet(n, a + 1); 
    } 
    else 
    { 
     int n_a2 = n_a; 
     int n_b2 = n_b; 

     a[t] = a[t-p]; 

     if (a[t] == 0) 
      n_a2--; 
     else 
      n_b2--; 

     if (a[t] == a[1]) 
      v++; 
     else 
      v = 0; 

     if ((u == (t - 1)) && (a[t-1] == a[1])) 
      u++; 

     if ((n_a2 >= 0) && (n_b2 >= 0) && !((t == n) && (u != n) && (a[n] == a[1]))) 
     { 
      if (u == v) { 
       int rev = check_rev(t, u); 

       if (rev == 0) 
        gen_bracelets(n_a2, n_b2, t + 1, p, r, u, v, rs); 

       if (rev == 1) 
        gen_bracelets(n_a2, n_b2, t + 1, p, t, u, v, 0); 
      } 
      else 
       gen_bracelets(n_a2, n_b2, t + 1, p, r, u, v, rs); 
     } 

     if (u == t) 
      u--; 

     if (a[t-p] == 0 && n_b > 0) 
     { 
      a[t] = 1; 

      if (t == 1) 
       gen_bracelets(n_a, n_b - 1, t + 1, t, 1, 1, 1, rs); 
      else 
       gen_bracelets(n_a, n_b - 1, t + 1, t, r, u, 0, rs); 
     } 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    int n_a, n_b; 

    if (argc < 3) 
    { 
     fprintf(stderr, "Usage: %s <a> <b>\n", argv[0]); 
     return -2; 
    } 

    n_a = atoi(argv[1]); 
    n_b = atoi(argv[2]); 

    if (n_a < 0 || n_b < 0) 
    { 
     fprintf(stderr, "a and b must be nonnegative\n"); 
     return -3; 
    } 

    n = n_a + n_b; 
    a = malloc((n + 1) * sizeof(int)); 

    if (!a) 
    { 
     fprintf(stderr, "could not allocate array\n"); 
     return -1; 
    } 

    a[0] = 0; 

    gen_bracelets(n_a, n_b, 1, 1, 0, 0, 0, 0); 

    free(a); 
    return 0; 
} 
0

यदि आपके पास केवल दो तत्व हैं, तो आपकी जगह बहुत छोटी है: 2^के बजाए के! 2^कश्मीर के माध्यम से 1 से सभी नंबरों के माध्यम से

  1. रन:

    इस तरह एक दृष्टिकोण की कोशिश करो।

  2. बाइनरी रूप में संख्या लिखें।
  3. अनुवाद एक करने के लिए सभी 0s और 1s ख के लिए। अब आपके पास क्रमपरिवर्तन है।
  4. अपने अनुक्रम को लें और चक्रीय क्रमपरिवर्तन और उलटा द्वारा 2k अनुक्रम उत्पन्न करें। आपको केवल इन 2k अनुक्रमों में से 1 का मूल्यांकन करने की आवश्यकता है।
  5. 2k अनुक्रमों में से, पहले वर्णमाला के प्रकार का चयन करें।
  6. यह देखने के लिए अपने लॉग की जांच करें कि आपने यह पहले से ही किया है या नहीं। यदि हां, तो छोड़ दें।
  7. यदि यह नया है, तो इसका मूल्यांकन करें, और "किए गए" लॉग में जोड़ें। (यदि स्थान परमिट है, तो आप "परिवार" के सभी 2k तत्वों को पूर्ण लॉग में जोड़ सकते हैं, ताकि आप चरण (3) के बाद चरण (6) को दाएं स्थानांतरित कर सकें। आप किसी के अनुक्रम के बजाय संख्या को भी स्टोर कर सकते हैं और ख के, में "किया" लॉग इन करें।)

आप जे संभव प्रतीकों है, बल्कि सिर्फ दो की तुलना में, एक ही बात है, लेकिन आधार जे बजाय आधार 2.

+0

वह 2 तत्वों के के-टुपल्स चाहता था, के तत्वों के जोड़े नहीं। तो 2^के सही है। – job

+0

आपके उत्तर के लिए धन्यवाद। दरअसल, कदम 1-3 मेरी पहली कोशिश थी, लेकिन वे सभी 2^के संभावनाएं उत्पन्न करेंगे। शेष या तो बहुत कुशल प्रतीत नहीं होता है। मुझे अभी भी सभी 2^के संभावनाओं के लिए कुछ करना है और महत्वपूर्ण कार्य जोड़ा गया है (प्रत्येक व्यक्ति के लिए मुझे दर्पण करने और इसे दो बार स्थानांतरित करने की आवश्यकता है, फिर परिणाम को सॉर्ट करें और इसकी तुलना किसी बड़े लॉग से करें रखना)। – Jordi

0

का उपयोग आप के लिए देख रहे हैं संयोजन - जो आदेश स्वतंत्र हैं। Matlab इस के साथ सही ढंग से गणना की!/एन! एम! जो संयोजनों की संख्या की गणना के लिए सटीक सूत्र है।

+0

लेकिन ओपी ऑर्डर के बारे में परवाह करता है - [ए बी बी बी बी बी] [बी बी बी बी बी बी] से अलग है। – caf

+0

आह। 'परिपत्र' उदाहरण को बिंदु बनाने के लिए तीन से अधिक तत्वों का उपयोग करने की आवश्यकता है। –

+0

नहीं, मुझे पहले से ही संयोजन पता है, क्योंकि मुझे पता है कि मैं कितना तत्व चाहता हूं। मुझे आदेश में दिलचस्पी है, यह सिर्फ इतना है कि बहुत सारे ऑर्डर मेरे जैसा दिखते हैं। एम = 3 और एन = 2 के लिए 10 अद्वितीय संयोजन हैं, मैं केवल * * 1 एबीबीबी * <- अद्वितीय 2 ababb * <- अद्वितीय 3 abbab <- रिवर्स + 2 4 प्राप्त करने के लिए दाएं स्थानांतरित करें abbba <- 1 प्राप्त करने के लिए दाएं स्थानांतरित करें <बाबा <- 1 6 बाबाब <- 2 7 babba <- 2 8 bbaab <- shift 2 * प्राप्त करने के लिए बाएं स्थानांतरित करने के लिए बाएं स्थानांतरित करें 9 bbaba <- 2 0 बीबीबीए प्राप्त करने के लिए विपरीत <- 1 – Jordi

0

मान लें कि आपके पास सभी क्रमिक क्रमों की एक सरणी है, आप सरणी की सामग्री को हैश में डाल सकते हैं। फिर इस (एक छोटे से जानवर बल है, लेकिन इसकी एक शुरुआत) काम करेगा:

for each (element in array of permutations){ 
    if (element exists in hash){ 
    remove each circular permutation of element in hash except for element itself 
    } 
} 
1

मुझे लगता है कि आप 2-ary मुक्त हार उत्पन्न करना चाहते हैं। लिंक, कागजात, और कुछ कोड के लिए this question देखें।

+0

यह प्रश्न मुफ्त हार/कंगन के बजाय निश्चित हार पर केंद्रित है (यह भी सच हो सकता है कि के = 2 का विशेष मामला कुछ महत्वपूर्ण अनुकूलन संभव हो सकता है)। सूची में – caf

+0

आइटम # 2 कंगन का सुझाव देने लगता है। केवल मूल या रिवर्स (दोनों नहीं) का मतलब है कि उन्हें समकक्ष के रूप में व्यवहार करना है। (ठीक है? क्या मैं # 2 गलत पढ़ रहा हूं?) –

+0

क्षमा करें मैं स्पष्ट नहीं था - आप सही हैं कि यह प्रश्न कंगन के बारे में है, लेकिन मेरा मतलब यह था कि जो प्रश्न आपने लिंक किया है वह निश्चित हार के बारे में है। – caf

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