Câu trả lời của Miff chắc chắn là thanh lịch. Vì tôi đã hoàn thành công việc của mình dù sao tôi cũng cung cấp nó. Điều tốt là tôi nhận được kết quả tương tự cho n = 500 :-)
Đặt d là số lượng ký tự khác nhau được phép, d = 4 trong trường hợp của bạn.
Đặt n là độ dài của chuỗi, cuối cùng bạn sẽ xem xét các giá trị chẵn của n.
Đặt u là số ký tự chưa ghép trong một chuỗi.
Đặt N (n, d, u) là số chuỗi có độ dài n, được xây dựng từ d các ký tự khác nhau và có các ký tự không ghép cặp. Hãy thử tính toán N.
Có khá nhiều trường hợp góc để quan sát:
u> d hoặc u> n => N = 0
u <0 => N = 0
n% 2! = u% 2 => N = 0.
Khi bước từ n đến n + 1, u phải tăng 1 hoặc giảm 1, vì vậy chúng ta có đệ quy theo
N (n, d, u) = f (N (n-1, d, u-1), N (n-1, d, u + 1))
Có bao nhiêu cách để giảm u một. Điều này là dễ dàng, bởi vì chúng ta phải ghép một trong những nhân vật không ghép đôi, điều này làm cho nó chỉ là u. Vì vậy, phần 2 của f sẽ đọc (u + 1) * N (n-1, d, u + 1), với cảnh báo tất nhiên là chúng ta phải quan sát rằng N = 0 nếu u + 1> n-1 hoặc u +1> d.
Một khi chúng ta đã hiểu điều này, thật dễ dàng để thấy phần đầu tiên của f là gì: chúng ta có thể tăng u bao nhiêu cách khi có các ký tự không ghép đôi u-1. Chà, chúng ta phải chọn một trong các ký tự (k- (u-1)) được ghép nối.
Vì vậy, có tính đến tất cả các trường hợp góc, công thức đệ quy cho N là
N (n, d, u) = (d- (u-1)) * N (n-1, d, u-1) + (u + 1) * N (n-1, d, u + 1)
Tôi sẽ không đọc lên trong http://en.wikipedia.org/wiki/Concittle_Mathatures làm thế nào để giải quyết đệ quy.
Thay vào đó tôi đã viết một số mã Java. Một lần nữa vụng về hơn một chút, như Java dù sao cũng do tính dài dòng của nó. Nhưng tôi đã có động lực để không sử dụng đệ quy, vì nó phá vỡ từ rất sớm, ít nhất là trong Java, khi ngăn xếp tràn ra ở mức 500 hoặc 1000 mức lồng nhau.
Kết quả cho n = 500, d = 4 và u = 0 là:
N (500, 4, 0) = 1339385758982834151185531311325002263201756014631917009304687985462938813906170153116497973519619822659493341146941433531483931607115392554498072196838958545795769042788035468026048125208904713757765805163872455056995809556627183222337328039422584942896842901774597806462162357229520744881314972303360
được tính trong 0,2 giây, do ghi nhớ kết quả trung gian. N (40000,4,0) tính toán trong chưa đầy 5 giây. Mã cũng ở đây: 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);
}
}