คำตอบของ Miff นั้นสง่างามแน่นอน ตั้งแต่ฉันมีของฉันเกือบเสร็จแล้วต่อไปฉันให้มันอย่างไรก็ตาม สิ่งที่ดีคือฉันได้รับผลลัพธ์เดียวกันสำหรับ n = 500 :-)
ให้ d เป็นจำนวนตัวอักษรต่าง ๆ ที่อนุญาต d = 4 ในกรณีของคุณ
ให้ n เป็นความยาวของสตริงในท้ายที่สุดคุณจะดูค่าที่เท่ากันของ n
ให้คุณเป็นจำนวนอักขระที่ไม่ได้จับคู่ในสตริง
ให้ N (n, d, u) เป็นจำนวนสตริงที่มีความยาว n ซึ่งสร้างจากอักขระที่แตกต่างกัน d และมีอักขระที่ไม่ได้จับคู่ ให้ลองคำนวณ N
มีบางกรณีมุมที่สังเกตได้:
u> d หรือ u> n => N = 0
คุณ <0 => N = 0
n% 2! = u% 2 => N = 0
เมื่อก้าวจาก n เป็น n + 1 คุณต้องเพิ่มขึ้น 1 หรือลดลง 1 ดังนั้นเราจึงเรียกซ้ำตาม
N (n, d, u) = f (N (n-1, d, u-1), N (n-1, d, u + 1)
มีกี่วิธีที่จะช่วยลดคุณทีละคน อันนี้ง่ายเพราะเราต้องจับคู่หนึ่งในตัวละครที่ไม่มีคู่ซึ่งทำให้มันเป็นแค่คุณ ดังนั้นส่วนที่ 2 ของ f จะอ่าน (u + 1) * N (n-1, d, u + 1) โดยมีข้อแม้แน่นอนว่าเราต้องสังเกตว่า N = 0 ถ้าคุณ + 1> n-1 หรือ u 1> d
เมื่อเราเข้าใจสิ่งนี้มันเป็นเรื่องง่ายที่จะเห็นว่าส่วนแรกของ f คือ: เราสามารถเพิ่มคุณได้กี่วิธีเมื่อมีตัวละครที่ไม่มีคู่ u-1 เราต้องเลือกหนึ่งในอักขระ (k- (u-1)) ที่ถูกจับคู่
ดังนั้นเมื่อคำนึงถึงทุกมุมกรณีสูตรแบบเรียกซ้ำสำหรับ N คือ
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วิธีแก้ปัญหาการเรียกซ้ำ
ฉันเขียนโค้ดจาวาแทน อีกเล็กน้อยเงอะงะมากขึ้นเช่นเดียวกับ Java ต่อไปเนื่องจากการใช้คำฟุ่มเฟื่อย แต่ฉันมีแรงจูงใจที่จะไม่ใช้การเรียกซ้ำเนื่องจากมันหยุดไปก่อนอย่างน้อยใน Java เมื่อกองซ้อนล้นที่ 500 หรือ 1,000 ระดับการซ้อน
ผลลัพธ์สำหรับ n = 500, d = 4 และ u = 0 คือ:
N (500, 4, 0) = 1339385758982834151185531311325002263201756014631917009304687985462938813906170153116497973519619822659493341146941433531483931607115392554498072196838958545795769042788035468026048125208904713757765805163872455056995809556627183222337328039422584942896842901774597806462162357229520744881314972303360
คำนวณใน 0.2 วินาทีเนื่องจากการจดจำผลลัพธ์ระดับกลาง N (40000,4,0) คำนวณในเวลาน้อยกว่า 5 วินาที รหัสด้วยที่นี่: 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);
}
}