her karakterin eşit zamanlar olması gerektiğinde karakter dizisi sayısı


9

Kafatasımı bir süredir bu probleme dayayordum ve bu gerçekten beni hayal kırıklığına uğratmaya başlıyor. Problem şu:

Ben bir karakter kümesine sahip, A, B, C, ve D. Uzunluğu ne zaman nve her karakter bile kez oluşmalıdır , bu karakterlerden bir dize kaç yoldan inşa edilebilir söylemek gerekir.

Örneğin, cevabı n = 24:

AA
BB
CC
DD

Bunun cevabı n = 440'tır. Bu geçerli dizelerden bazıları:

AAAA
AABB
CACA
DAAD
BCCB

Bir mantık bulmaya sıkıştım. Bunun için bir DP çözümü olabileceğini hissediyorum. Bu yoldan kaba-zorlamam söz konusu değil: çözümlerin sayısı hızla büyük sayılara ulaşıyor.

Her türlü fikri kağıda çizmeye çalıştım, boşuna. Bu fikirlerin neredeyse tamamı, karmaşıklıkları çok büyük olduğu için atmak zorunda kaldım. Çözüm için verimli olmalıdır n = 10^4.

Fikirlerimden biri, gerçek dizeleri asla takip etmemekti, ancak her karakterin çift veya tek kez görünüp görünmediği. Bu mantığı uygulamak için bir yol bulamadım.

Biri bana yardım edebilir mi?


3
Dizeleri numaralandırmanız veya dizelerin sayısını hesaplamanız gerekiyor mu? Yalnızca dizelerin sayısına ihtiyacınız varsa , miktarı doğrudan hesaplamak için birleştiriciyi kullanabilirsiniz .

@Snowman Yalnızca olası dizelerin sayısı gereklidir. Ancak burada kombinatorik kullanabilmem pek olası değil. Bir yol olsa bile, sorunun saf matematikle çözülmemesi gerektiğinden eminim ve bu nedenle istemiyorum. Yoksa ne demek istediniz?
Olavi Mustanoja

2
Elbette kombinatorik kullanabilirsiniz. Bir uzunluk N dizesi için, {AA, BB, CC, DD} 'nin tüm kombinasyonlarını alın. Her kombinasyon için benzersiz permütasyonlar edinin. Ardından, her bir kombinasyonun sonuçlarını bir dizi benzersiz permütasyon halinde birleştirin. Bunu nasıl yapacağımdan emin değilim, öncelikle teklik kısıtlaması nedeniyle, ama eminim bir yol var.

@Snowman Ne demek istediğini anlıyorum. Ancak bu en azından kombinasyonların depolanmasını gerektirmez mi? Benzersiz permütasyonların sayısını almak bunu gerektirir ve kombinasyonların sayısı çok hızlı bir şekilde büyüyemediğim oranlarda büyür.
Olavi Mustanoja

1
Muhtemelen. Kesin olarak bilmek için kombinatoriklerle yeteri kadar bilgili değilim. Belki Mathematics.SE buna benzer bir sorusu var? Şu an bunu yapmak için zamanım yok, ama bu ilginç bir problem. Bunu düşünüp tekrar kontrol edeceğim.

Yanıtlar:


5

Farklı karakterler (örneğin , sizin durumunuz) kullanarak f(n,d)(çift) uzunluktaki permütasyon sayısını veren bir işlev olarak ayarlayın .ndd=4

Açıkça f(0,d) = 1ve f(n,1) = 1sadece bir karakteriniz veya sıfır boşluğunuz olduğunda tek bir düzenleme olduğu için.

Şimdi indüksiyon adımı:

dKarakterleri kullanarak geçerli bir dize oluşturmak için, karakterleri kullanarak daha kısa ve eşit uzunluktaki dizeleri alın d-1ve bu yeni karakterin katlarını ekleyerek uzunluğunu tamamlayın. Düzenlemelerin sayısı , yeni basamağa sahip olmak için toplam dize uzunluğunun dışındaki yerleri choose(n,n_newdigits)seçebilmenizdir n_newdigitve geri kalanı orijinal dize tarafından sırayla doldurulur.

Bunu R'de saf özyineleme kullanarak uygulamak için yaptım:

f <- function(n,d)
{
  if(n==0) return(1)
  if(d==1) return(1)
  retval=0
  for (i in seq(from=0, to=n, by=2)) retval=retval+f(n-i,d-1)*choose(n,i)
  return(retval)
}

f(4,4)
# 40    

f(500,4)
# 1.339386e+300 takes about 10 secs

İlgilendiğiniz sayılar için, sayıları iki boyutlu bir dizide saklamanın daha verimli olacağını ve d'yi artarak yinelediğini düşünürdüm, ancak bu dil seçiminize bağlı olabilir.


4

Miff'in cevabı kesinlikle zarif. Benimkini neredeyse bitirdiğim için yine de sağlıyorum. İyi olan şey, n = 500 için aynı sonucu elde etmem :-)

Izin vermek izin verilen farklı karakter sayısı d olsun, senin durumunda d = 4.

N dizenin uzunluğu olsun, n sonunda eşit n değerlerine bakacaksınız.

U bir dizedeki eşleştirilmemiş karakter sayısı olsun.

N (n, d, u), d farklı karakterden oluşturulan ve u eşleştirilmemiş karakterlere sahip olan n uzunluğundaki dizelerin sayısı olsun. N'yi hesaplamaya çalışalım.

Gözlemlenmesi gereken birkaç köşe vakası var:

u> d veya u> n => N = 0

u <0 => N = 0

n% 2! = u% 2 => N = 0.

N'den n + 1'e adım attığınızda, u 1 artmalı veya 1 azalmalıdır, bu nedenle

N (n, d, u) = f (N (n-1, d, u-1), N (n-1, d, u + 1))

U bir azaltmak için kaç yolu vardır. Bu kolaydır, çünkü u eşleştirilmemiş karakterlerden birini eşleştirmeliyiz, bu da sadece u yapar. Böylece f'nin 2. kısmı (u + 1) * N (n-1, d, u + 1) okuyacaktır, tabii ki u + 1> n-1 veya u ise N = 0 olduğunu gözlemlemeliyiz. + 1> ö.

Bunu anladıktan sonra, f'nin ilk bölümünün ne olduğunu görmek kolaydır: u-1 eşleştirilmemiş karakterler olduğunda u kaç yolla artırabiliriz. Eşleştirilmiş olan (k- (u-1)) karakterlerden birini seçmeliyiz.

Bu nedenle, tüm köşe vakalarını dikkate alarak, N için özyinelemeli formül

N (n, d, u) = (d- (u-1)) * N (n-1, d, u-1) + (u + 1) * N (n-1, d, u + 1)

Http://en.wikipedia.org/wiki/Concrete_Mathematics özyinelemenin nasıl çözüleceğini okumayacağım .

Bunun yerine bazı Java kodları yazdım. Yine biraz daha beceriksiz, Java da ayrıntılarından dolayı zaten. Ama özyineleme kullanmama motivasyonum vardı, çünkü yığın 500 veya 1000 yuvalama seviyesine taştığında, en azından Java'da çok erken kırılıyor.

N = 500, d = 4 ve u = 0 için sonuç:

N (500, 4, 0) = 1339385758982834151185531311325002263201756014631917009304687985462938813906170153116497973519619822659493341146941433531483931607115392554498072196838958545795769042788035468026048125208904713757765805163872455056995809556627183222337328039422584942896842901774597806462162357229520744881314972303360

ara sonuçların ezberlenmesi nedeniyle 0.2 saniyede hesaplanmıştır. N (40000,4,0) 5 saniyeden az sürede hesaplar. Kodu da buraya yazın: http://ideone.com/KvB5Jv

import java.math.BigInteger;

public class EvenPairedString2 {
  private final int nChars;  // d above, number of different chars to use
  private int count = 0;
  private Map<Task,BigInteger> memo = new HashMap<>();

  public EvenPairedString2(int nChars) {
    this.nChars = nChars;
  }
  /*+******************************************************************/
  // encodes for a fixed d the task to compute N(strlen,d,unpaired).  
  private static class Task {
    public final int strlen;
    public final int unpaired;

    Task(int strlen, int unpaired) {
      this.strlen = strlen;
      this.unpaired = unpaired;
    }
    @Override
    public int hashCode() {
      return strlen*117 ^ unpaired;
    }
    @Override
    public boolean equals(Object other) {
      if (!(other instanceof Task)) {
        return false;
      }
      Task t2 = (Task)other;
      return strlen==t2.strlen && unpaired==t2.unpaired;
    }
    @Override
    public String toString() {
      return "("+strlen+","+unpaired+")";
    }
  }
  /*+******************************************************************/
  // return corner case or memorized result or null  
  private BigInteger getMemoed(Task t) {
    if (t.strlen==0 || t.unpaired<0 || t.unpaired>t.strlen || t.unpaired>nChars
        || t.strlen%2 != t.unpaired%2) {
      return BigInteger.valueOf(0);
    }

    if (t.strlen==1) {
      return BigInteger.valueOf(nChars);
    }
    return memo.get(t);
  }

  public int getCount() {
    return count;
  }

  public BigInteger computeNDeep(Task t) {
    List<Task> stack = new ArrayList<Task>();
    BigInteger result = null;
    stack.add(t);

    while (stack.size()>0) {
      count += 1;
      t = stack.remove(stack.size()-1);
      result = getMemoed(t);
      if (result!=null) {
        continue;
      }

      Task t1 = new Task(t.strlen-1, t.unpaired+1);
      BigInteger r1 = getMemoed(t1);
      Task t2 = new Task(t.strlen-1, t.unpaired-1);
      BigInteger r2 = getMemoed(t2);
      if (r1==null) {
        stack.add(t);
        stack.add(t1);
        if (r2==null) {
          stack.add(t2);
        }
        continue;
      }
      if (r2==null) {
        stack.add(t);
        stack.add(t2);
        continue;
      }
      result = compute(t1.unpaired, r1, nChars-t2.unpaired, r2);
      memo.put(t,  result);
    }
    return result;
  }
  private BigInteger compute(int u1, BigInteger r1, int u2, BigInteger r2) {
    r1 = r1.multiply(BigInteger.valueOf(u1));
    r2 = r2.multiply(BigInteger.valueOf(u2));
    return r1.add(r2);
  }
  public static void main(String[] argv) {
    int strlen = Integer.parseInt(argv[0]);
    int nChars = Integer.parseInt(argv[1]);

    EvenPairedString2 eps = new EvenPairedString2(nChars);

    BigInteger result = eps.computeNDeep(new Task(strlen, 0));
    System.out.printf("%d: N(%d, %d, 0) = %d%n", 
                      eps.getCount(), strlen, nChars, 
                      result); 
  }
}

2

Bir çözüm bulmaya çalıştım ama başarısız oldum ve Mathematics.StackExchange ile aynı soruyu sordum . Rus May sayesinde , Common Lisp'te bir çözüm var:

(defun solve (n)
  (if (evenp n)
      (/ (+ (expt 4 n) (* 4 (expt 2 n))) 8)
      0))

Bu, değerinin tek değerleri için her zaman 0 değerini döndürür n. Çünkü n = 500, SBCL ile çıktı :

* (time (solve 500))

    Evaluation took:
      0.000 seconds of real time
      0.000000 seconds of total run time (0.000000 user, 0.000000 system)
      100.00% CPU
      51,100 processor cycles
      0 bytes consed

    1339385758982834151185531311325002263201756014631917009304687985462938813906170153116497973519619822659493341146941433531483931607115392554498072196838958545795769042788035468026048125208904713757765805163872455056995809556627183222337328039422584942896842901774597806462162357229520744881314972303360
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.