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);
}
}