số chuỗi, khi mỗi ký tự phải xảy ra số lần chẵn


9

Tôi đã đập hộp sọ của tôi về vấn đề này một thời gian và nó thực sự bắt đầu làm tôi thất vọng. Vấn đề là:

Tôi có một tập hợp các ký tự, A, B, C, và D. Tôi phải cho biết có bao nhiêu cách một chuỗi có thể được xây dựng từ các ký tự đó, khi độ dài là nvà mỗi ký tự phải xảy ra thậm chí nhiều lần.

Ví dụ: câu trả lời cho n = 2là 4:

AA
BB
CC
DD

Câu trả lời n = 4là 40. Một số chuỗi hợp lệ là:

AAAA
AABB
CACA
DAAD
BCCB

Tôi bị mắc kẹt khi đưa ra một logic. Tôi cảm thấy như có thể có một giải pháp DP cho việc này. Brute-buộc tôi vượt qua điều này là không cần thiết: số lượng các giải pháp nhanh chóng phát triển thành số lượng lớn.

Tôi đã thử vẽ tất cả các loại ý tưởng trên giấy, nhưng không có kết quả. Hầu như tất cả những ý tưởng đó tôi phải loại bỏ vì độ phức tạp của chúng quá lớn. Các giải pháp nên được hiệu quả cho n = 10^4.

Một trong những ý tưởng của tôi là không bao giờ theo dõi các chuỗi thực tế, mà chỉ là liệu mỗi nhân vật đã xuất hiện chẵn hay lẻ. Tôi không thể đưa ra một cách để áp dụng logic này.

Ai giúp tôi với?


3
Bạn có cần liệt kê các chuỗi, hoặc tính số lượng chuỗi không? Nếu bạn chỉ cần số lượng chuỗi, bạn có thể sử dụng tổ hợp để tính trực tiếp số lượng.

@Snowman Chỉ cần số lượng chuỗi có thể là cần thiết. Tuy nhiên tôi thấy không chắc là tôi có thể sử dụng tổ hợp ở đây. Thậm chí nếu có một cách nào, tôi chắc chắn rằng vấn đề không phải để được giải quyết với toán học thuần túy, và vì lý do đó không muốn. Hay ý của bạn là gì?
Olavi Mustanoja

2
Chắc chắn bạn có thể sử dụng tổ hợp. Đối với một chuỗi có độ dài N, hãy lấy tất cả các kết hợp của {AA, BB, CC, DD}. Đối với mỗi kết hợp, có được hoán vị độc đáo. Sau đó kết hợp các kết quả cho mỗi kết hợp thành một tập hợp hoán vị duy nhất. Tôi không chắc chắn làm thế nào để làm điều này, chủ yếu là do các ràng buộc duy nhất, nhưng tôi chắc chắn có một cách.

@Snowman Tôi hiểu ý của bạn. Nhưng sẽ không yêu cầu lưu trữ ít nhất là sự kết hợp? Lấy số lượng hoán vị duy nhất đòi hỏi điều này và số lượng kết hợp tăng rất nhanh thành tỷ lệ tôi không thể lưu trữ.
Olavi Mustanoja

1
Có khả năng. Tôi không đủ thành thạo với tổ hợp để biết chắc chắn. Có lẽ Toán học.SE có một câu hỏi tương tự như thế này? Tôi không có thời gian để nghiên cứu về nó ngay bây giờ, nhưng đây là một vấn đề thú vị. Tôi sẽ suy nghĩ về nó và kiểm tra lại.

Câu trả lời:


5

Thiết lập f(n,d)như một hàm cho số lượng hoán vị của độ dài (chẵn) nbằng dcác ký tự riêng biệt (nghĩa là d=4trong trường hợp của bạn).

Rõ ràng f(0,d) = 1f(n,1) = 1như chỉ có một sự sắp xếp khi bạn chỉ có một ký tự hoặc không gian trống.

Bây giờ là bước cảm ứng:

Để tạo một chuỗi hợp lệ bằng cách sử dụng các dký tự, hãy lấy bất kỳ chuỗi có độ dài chẵn ngắn hơn bằng cách sử dụng các d-1ký tự và làm cho nó có độ dài bằng cách thêm vào một bội số của ký tự mới này. Số lượng sắp xếp là choose(n,n_newdigits)bởi vì bạn có thể chọn các n_newdigitvị trí trong tổng chiều dài chuỗi để có chữ số mới và phần còn lại được điền bởi chuỗi gốc theo thứ tự.

Để thực hiện điều này bằng cách sử dụng đệ quy ngây thơ trong R, tôi đã là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

đối với loại số bạn quan tâm, tôi đã nghĩ rằng việc lưu trữ số trong một mảng hai chiều sẽ hiệu quả hơn và lặp đi lặp lại khi tăng d, nhưng điều này có thể phụ thuộc vào lựa chọn ngôn ngữ của bạn.


4

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

2

Tôi đã cố gắng đưa ra một giải pháp nhưng không thành công và hỏi cùng một câu hỏi trên Toán học.StackExchange . Cảm ơn Rus May , đây là một giải pháp, trong Common Lisp:

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

Điều này luôn trả về 0 cho các giá trị lẻ của n. Đối với n = 500, đây là đầu ra với SBCL :

* (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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.